xóa ax vs ax = không xác định


138

Có sự khác biệt đáng kể nào trong việc làm một trong hai?

delete a.x;

đấu với

a.x = undefined;

Ở đâu

a = {
    x: 'boo'
};

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

(Tôi không tính đến những thứ như "thích V8 không sử dụng deletetốt hơn" )


2
Toán tử xóa loại bỏ hoàn toàn một thuộc tính. Đặt thuộc tính thành không xác định sẽ loại bỏ giá trị. Đặ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 hoàn hảo nếu bạn thích: jsperf.com/delete-vs-undDef-vs-null/3
j08691

1
@ j08691 Nit: Nó không xóa giá trị. Nó gán undefinedlàm giá trị, vẫn là một ..

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.
Juan Mendes

Câu trả lời:


181

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

a.x = undefined

có nghĩa là nó a.hasOwnProperty("x")vẫn sẽ trả về true và do đó, nó vẫn sẽ hiển thị trong một for invòng lặp và trongObject.keys()

delete a.x

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

Cách chúng giống nhau là bạn không thể biết nếu một tài sản tồn tại bằng cách thử nghiệm

if (a.x === undefined)

Những gì bạn không nên làm nếu bạn đang cố xác định xem một tài sản có tồn tại hay không, 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'))

Theo chuỗi nguyên mẫu (được đề cập bởi zzzzBov ) Gọi deletesẽ 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 được xâu chuỗi 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 được kế thừa Nếu thuộc tính bạn đang cố xóa được kế thừa, deletesẽ không ảnh hưởng đến nó. Đó là, deletechỉ xóa các thuộc tính khỏi chính đối tượng, không phải các 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 đảm bảo giá trị của một đối tượng sẽ không được xác định, deletesẽ không hoạt động khi thuộc tính được kế thừa, bạn sẽ phải đặt (ghi đè) nó undefinedtrong trường hợp đó. Trừ khi nơi đang kiểm tra nó sẽ sử dụng hasOwnProperty, nhưng có thể sẽ không an toàn khi cho rằng mọi nơi kiểm tra sẽ sử dụnghasOwnProperty


1
"x" in acũng sẽ trở lại truevới cái trước, và falsevới cái sau Đầu ra của Object.keyscũng sẽ khác nhau.
cô đơn

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

@Nico Bởi 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 đừng bao giờ sử dụng nó. Nhưng nếu bạn đang kiểm tra undefined, bạn cũng có thể chỉ kiểm tra if (a.x), trừ khi số đó và 0 là hợp lệ
Juan Mendes

33

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

Được delete a.xa.x = undefinedtương đương?

Không.

Cái trước loại bỏ khóa khỏi biến, cái sau đặt khóa có giá trị là 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 các đối tượng và khi hasOwnPropertyđược sử dụng.

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 ra một 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ề việc deletecho phép nó đi lên chuỗi nguyên mẫu
Juan Mendes

4

Nếu a.xlà hàm setter, a.x = undefinedsẽ gọi hàm trong khi delete a.xsẽ không gọi hàm.


3

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


2

Những cái tên hơi khó hiểu. a.x = undefinedchỉ đặt tài sản thành undefined, nhưng tài 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)
[]

1

REPL từ nút 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

1

Tôi chắc rằng 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.psẽ có undefinednhư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ị .

deletelà toán tử cho phép bạn lấy từ o1(hoặc một đối tượng khác có giá trị được gán cho thuộc tính của nó p) o2theo cách đó : delete o1.p;.

Hoạt động ngược lại được thực hiện bằng cách chỉ định một giá trị ( undefinedtrong ví dụ này nhưng nó có thể là một cái gì đó 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ẽ

  • xóa tài sản pkhỏi đối tượng nếu nó có

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

o.p = undefined; sẽ

  • thêm một thuộc tính pvào đối tượng nếu nó chưa có thuộc tính và đặt giá trị của nó thànhundefined

  • 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 năng, deletexấu vì nó sửa đổi cấu trúc của đối tượng (giống như thêm một thuộc tính mới nếu bạn chưa khởi tạo nó trong hàm tạo).

Trong khi đó, thiết lập giá trị để undefinedphát hành nội dung là tốt nhưng không buộc phải sửa đổi cấu trúc.


1

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

Khi bạn xóa bất kỳ khóa nào khỏi một đối tượng bằng cách sử dụng xóa, thực tế nó sẽ xóa liên kết giữa khóa đó với đối tượng mẹ của nó và các 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ó, 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 được xác định.

Sử dụng không xác định thay vì sử dụng từ khóa xóa là một thực tế xấu, vì nó không giải phóng vị trí bộ nhớ của khóa đó.

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

ví dụ

var a = {};
a.d = undefined;
console.log(a); // this will print { d: undefined }

xóa không thể được làm việc với các thuộc tính được 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ứ nơi nào "lớp" được tham chiếu.
Juan Mendes

@JuanMendes, bạn có thể cho tôi tham khảo được không.
Laxmikant Dange

3
Xem Việc sử dụng từ khóa xóa có ảnh hưởng đến tối ưu hóa v8 của một đối tượng không? TL; DR as a general rule of thumb, using 'delete' makes thing slower.developers.google.com/v8/design To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates hidden classes behind the scenes. In V8, an object changes its hidden class when a new property is added. , và cuối cùng là smashingmagazine.com/2012/11/ Khăn
Juan Mendes

1

Sử dụng một mảng, thay vì một đối tượng, tôi có thể hiển thị rằng xóa sử dụng ít bộ nhớ heap hơn không xác định.

Ví dụ: mã này sẽ không hoàn thành:

let y = 1;
let ary = [];
console.log("Fatal Error Coming Soon");
while (y < 4294967295)
{
    ary.push(y);
    ary[y] = undefined;
    y += 1;
}
console(ary.length);

Nó tạo ra lỗi này:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory.

Vì vậy, như bạn có thể thấy undefinedthực sự chiếm bộ nhớ heap.

Tuy nhiên, nếu bạn cũng là deletemục ary (thay vì chỉ đặt thành undefined), mã sẽ từ từ kết thúc:

let x = 1;
let ary = [];
console.log("This will take a while, but it will eventually finish successfully.");
while (x < 4294967295)
{
    ary.push(x);
    ary[x] = undefined;
    delete ary[x];
    x += 1;
}
console.log(`Success, array-length: ${ary.length}.`);

Đây là những ví dụ cực đoan, nhưng chúng đưa ra quan điểm deleterằng tôi chưa thấy ai nhắc đến ở bất cứ đâu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.