2013-02-19 16 views
93

Có sự khác biệt đáng kể nào trong việc thực hiện một trong hai điều này không?xóa a.x vs a.x = undefined

delete a.x; 

vs

a.x = undefined; 

nơi

a = { 
    x: 'boo' 
}; 

có thể nói rằng họ là tương đương?

(Tôi không tính đến các tài khoản như "V8 likes not using delete better")

+2

Toán tử xóa sẽ xóa hoàn toàn thuộc tính. Đặt thuộc tính thành không xác định sẽ xóa giá trị. Đặt một thuộc tính thành null sẽ thay đổi giá trị thành giá trị null. Đây là một thử nghiệm perf nếu bạn thích: http://jsperf.com/delete-vs-undefined-vs-null/3 – j08691

+1

@ j08691 Nit: Nó không loại bỏ giá trị. Nó gán 'undefined' làm giá trị, mà vẫn là một .. –

+0

Bạn nên nói về lý do tại sao bạn quan tâm đến điều này, sau đó câu trả lời có thể phục vụ cho vấn đề thực tế của bạn. –

Trả lời

121

Chúng không tương đương. Sự khác biệt chính là thiết

a.x = undefined 

nghĩa là a.hasOwnProperty("x") vẫn sẽ trở thành sự thật, và do đó, nó vẫn sẽ hiển thị trong một vòng lặp for in, và trong Object.keys()

delete a.x 

nghĩa là a.hasOwnProperty("x") sẽ trả về false

Cách chúng giống nhau là bạn không thể biết được thuộc tính có tồn tại hay không bằng cách thử nghiệm

if (a.x === undefined) 

nào bạn không nên làm nếu bạn đang cố gắng để xác định xem một tài sản tồn tại, bạn nên luôn luôn sử dụng

// If you want inherited properties 
if ('x' in a) 

// If you don't want inherited properties 
if (a.hasOwnProperty('x')) 

Tiếp nối chuỗi nguyên mẫu (được đề cập bởi zzzzBov) Gọi delete sẽ cho phép nó đi lên chuỗi nguyên mẫu, trong khi đặt giá trị thành không xác định sẽ không tìm kiếm thuộc tính trong các nguyên mẫu bị xích http://jsfiddle.net/NEEw4/1/

var obj = {x: "fromPrototype"}; 
var extended = Object.create(obj); 
extended.x = "overriding"; 
console.log(extended.x); // overriding 
extended.x = undefined; 
console.log(extended.x); // undefined 
delete extended.x; 
console.log(extended.x); // fromPrototype 

Xóa các thuộc tính thừa kế Nếu thuộc tính bạn đang cố gắng xóa được kế thừa, delete sẽ không ảnh hưởng đến nó. Tức là, delete chỉ xóa thuộc tính khỏi đối tượng, chứ không phải thuộc tính được kế thừa.

var obj = {x: "fromPrototype"}; 
var extended = Object.create(obj); 
delete extended.x; 
console.log(extended.x); // Still fromPrototype 

Do đó, nếu bạn cần phải chắc chắn giá trị của một đối tượng sẽ được undefined, delete sẽ không hoạt động khi tài sản được thừa kế, bạn sẽ phải thiết lập (override) nó để undefined trong trường hợp đó. Trừ khi nơi đó là kiểm tra nó sẽ sử dụng hasOwnProperty, nhưng nó có khả năng sẽ không được an toàn để giả định rằng ở khắp mọi nơi để kiểm tra nó sẽ sử dụng hasOwnProperty

+1

'" x "trong a' cũng sẽ trả về' true' với giá trị cũ, và 'false' với giá trị thứ hai. Đầu ra của 'Object.keys' cũng sẽ khác nhau. – lonesomeday

+0

tại sao bạn nói rằng tôi không nên kiểm tra không xác định? có vẻ đủ hợp lý với tôi. – bevacqua

+0

@Nico Vì điều đó sẽ không cho bạn biết nếu một tài sản tồn tại. Tôi không nói không bao giờ sử dụng nó. Nhưng nếu bạn đang kiểm tra 'undefined', bạn cũng có thể kiểm tra' if (ax) ', trừ khi nó cho số và 0 là hợp lệ –

25

Để diễn giải câu hỏi:

Are delete a.xa.x = undefined tương đương ?

số

Cựu loại bỏ phím từ biến, các bộ sau phím với một giá trị của undefined.Điều này tạo ra sự khác biệt khi lặp qua các thuộc tính của đối tượng và khi sử dụng hasOwnProperty.

a = { 
    x: true 
}; 
a.x = undefined; 
a.hasOwnProperty('x'); //true 
delete a.x; 
a.hasOwnProperty('x'); //false 

Ngoài ra, điều này sẽ tạo sự khác biệt đáng kể khi chuỗi nguyên mẫu có liên quan.

function Foo() { 
    this.x = 'instance'; 
} 
Foo.prototype = { 
    x: 'prototype' 
}; 
a = new Foo(); 
console.log(a.x); //'instance' 

a.x = undefined; 
console.log(a.x); //undefined 

delete a.x; 
console.log(a.x); //'prototype' 
+2

+1 Điểm tuyệt vời về' delete' cho phép nó đi lên chuỗi nguyên mẫu –

1

Nút REPL này sẽ minh họa sự khác biệt.

> a={ x: 'foo' }; 
{ x: 'foo' } 
> for (var i in a) { console.log(i); }; 
x 
undefined 
> a.x=undefined; 
undefined 
> for (var i in a) { console.log(i); }; 
x 
undefined 
> delete a.x; 
true 
> for (var i in a) { console.log(i); }; 
undefined 
2

Tên có chút khó hiểu. a.x = undefined chỉ bộ tài sản để undefined, nhưng bất động sản vẫn còn đó:

> var a = {x: 3}; 
> a.x = undefined; 
> a.constructor.keys(a) 
["x"] 

delete thực sự xóa nó:

> var a = {x: 3}; 
> delete a.x; 
> a.constructor.keys(a) 
[] 
2

Có có một sự khác biệt. Nếu bạn sử dụng delete a.x thì x không phải là bất kỳ thuộc tính nào của a, nhưng nếu bạn sử dụng a.x=undefined thì đó là thuộc tính nhưng giá trị của nó không được xác định.

1

Tôi chắc chắn bạn có thể thấy sự khác biệt giữa var o1 = {p:undefined};var o2 = {};.

Trong cả hai trường hợp, o.p sẽ undefined nhưng trong trường hợp đầu tiên, đó là vì đó là giá trị và trong trường hợp thứ hai vì không có giá trị.

delete là các nhà điều hành cho phép bạn nhận được từ o1 (hoặc một đối tượng mà có một giá trị được gán cho bất động sản p của nó) để o2 theo cách đó: delete o1.p;.

Thao tác đảo ngược được thực hiện bằng cách chỉ định giá trị (undefined trong ví dụ này nhưng có thể là một thứ khác) cho thuộc tính o1.p = undefined;.

Vì vậy, không, chúng không tương đương.


delete o.p; sẽ

  • loại bỏ các tài sản p từ đối tượng nếu nó có một

  • không làm gì khác

o.p = undefined; sẽ

  • thêm một tài sản p đến đối tượng nếu nó không có tiểu sử nào và thiết lập giá trị của nó để undefined

  • chỉ cần thay đổi giá trị của tài sản nếu đối tượng đã có nó


Từ góc độ hiệu suất, deletexấu vì nó sửa đổi cấu trúc của đối tượng (giống như thêm thuộc tính mới nếu bạn chưa khởi tạo nó trong hàm tạo).

Trong khi đặt giá trị thành undefined cũng giải phóng nội dung nhưng không buộc phải sửa đổi cấu trúc.

0

Đối tượng chỉ đơn giản là biểu diễn cây, có nghĩa là, trong bộ nhớ, điểm gốc trỏ đến các vị trí bộ nhớ khác nhau, nơi các khóa của đối tượng đó được lưu trữ. và vị trí đó trỏ đến vị trí khác nơi giá trị thực của khóa đó được lưu trữ hoặc vị trí lưu trữ các khóa con hoặc vị trí lưu trữ các giá trị mảng.

Khi bạn xóa bất kỳ khóa nào khỏi đối tượng bằng cách xóa, thực sự nó xóa liên kết giữa khóa đó và đối tượng mẹ và vị trí bộ nhớ của khóa và giá trị của nó được giải phóng để lưu trữ thông tin khác.

Khi bạn cố gắng xóa bất kỳ khóa nào bằng cách đặt không xác định làm giá trị của nó, thì bạn chỉ cần đặt giá trị của nó, chứ không xóa khóa đó. Điều đó có nghĩa là vị trí bộ nhớ khóa vẫn được liên kết với đối tượng cha của nó và giá trị nếu khóa không xác định.

sử dụng không xác định thay vì sử dụng từ khóa xóa là thực tiễn không tốt vì không phát hành vị trí bộ nhớ của khóa đó.

Ngay cả khóa không có mặt và nếu bạn đặt không xác định, thì khóa đó sẽ được tạo với giá trị 'không xác định'.

ví dụ: var a = {} a.d = undefined; console.log (a); // thao tác này sẽ in {d: undefined}

xóa không thể làm việc với các thuộc tính kế thừa vì thuộc tính đó không phải là một phần của đối tượng con đó.

+1

Lưu ý rằng các công cụ mới hơn thích bạn không xóa các khóa, bởi vì khi bạn thực hiện công cụ cần tạo một lớp mới cho nó và cập nhật nó ở bất cứ đâu "lớp" được tham chiếu. –

+0

@JuanMendes, Bạn có thể đưa ra bất kỳ tham chiếu nào không. –

+2

Xem [Sử dụng xóa từ khóa ảnh hưởng đến tối ưu hóa v8 của một đối tượng?] (Https://groups.google.com/forum/#!topic/v8-users/zE4cOHBkAnY) TL; DR 'như một quy luật chung của ngón tay cái, sử dụng 'xóa' làm cho mọi thứ chậm hơn. 'và https://developers.google.com/v8/design' Để giảm thời gian cần thiết để truy cập các thuộc tính JavaScript, V8 không sử dụng tra cứu động để truy cập các thuộc tính. Thay vào đó, V8 tự động tạo ra các lớp ẩn đằng sau hậu trường. Trong V8, một đối tượng thay đổi lớp ẩn của nó khi một thuộc tính mới được thêm vào.' và cuối cùng là https://www.smashingmagazine.com/2012/11/writing-fast-memory-efficient-javascript/ –