2012-01-20 33 views
49

Hành vi của toán tử xóa có vẻ là very complicated and there are many misunderstandings about what it actually does. Đối với tôi, có vẻ như việc gán lại một cái gì đó cho undefined sẽ đáng tin cậy hơn làm những gì bạn mong đợi.Mục đích của toán tử xóa trong Javascript là gì?

Tôi chưa bao giờ thấy từ khóa delete trong Javascript thực sự được sử dụng trong mã không phải mẫu và tôi tự hỏi liệu nó có đặc biệt hữu ích cho bất kỳ thứ gì không. delete có bất kỳ mục đích nào không thể đạt được bằng cách chỉ định lại undefined không? Có được sử dụng ở tất cả các thư viện nổi tiếng (ví dụ: jQuery, dojo, xương sống, v.v.) không?

+0

Hành vi của 'xóa' không phức tạp chút nào.Nhưng nó ** thực sự ** không nên được gọi là 'xóa'. JavaScript tương tự như cú pháp C++, sử dụng toán tử C++ nhưng làm điều gì đó * hoàn toàn khác biệt * với nó là một chút oops và đã gây ra tất cả sự nhầm lẫn này. (Nếu nó được gọi là 'loại bỏ', tôi cá là mọi người sẽ không bị bối rối.) –

+0

http://perfectionkills.com/understanding-delete/ – Raghu

Trả lời

61

Xóa có bất kỳ mục đích nào không thể đạt được bằng cách chỉ định lại cho không xác định không?

Có. Nếu bạn muốn hiển thị thuộc tính từ nguyên mẫu hoặc gây ra in, hasOwnPropertyfor (...in...) để không ghi lại thuộc tính là hiện tại thì delete là thích hợp.

var set = {}; 

set._x = true; 

alert('_x' in set); // true 

set._x = undefined; 

alert('_x' in set); // true 

delete set._x; 

alert('_x' in set); // false 

EDIT: Là T.J. Crowder giải thích:

Mục đích của các nhà điều hành delete là để loại bỏ hoàn toàn một tài sản từ một đối tượng, trong khi thiết lập một tài sản để undefined chỉ bộ tài sản để undefined.

này quan trọng theo đúng nghĩa của nó, nhưng nó cũng có vấn đề khi bạn đang sử dụng thừa kế, bởi vì nếu O xuất phát từ P

var P = { prop: 42 }; 
var O = Object.create(P); // P is O's prototype. 

khi bạn lấy O.prop, bạn sẽ có được giá trị của prop từ O nếu O có một thuộc tính với tên đó (ngay cả khi giá trị của nó là không xác định), nhưng nếu O không có thuộc tính gì cả, thì giá trị sẽ được lấy ra từ P.prop thay thế.

alert(O.prop); // "42" since O doesn't have its own prop, but P does. 
O.prop = undefined; 
alert(O.prop); // "undefined" since O has its own prop. 
delete O.prop; 
alert(O.prop); // "42" since the delete "unmasked" P.prop. 
0

Vâng, bạn sẽ kết thúc với một phần tử trong đối tượng chứa giá trị undefined. Chìa khóa sẽ không biến mất.

9

Nếu bạn làm

delete Foo.Bar; 

nó xóa Bar tài sản từ đối tượng Foo hoàn toàn

Foo.Bar = undefined 

chỉ đơn thuần là thiết đặt thuộc tính Bar để xác định và Foo.Bar vẫn còn tồn tại

1

Bạn có thể kiểm tra câu trả lời của liên kết sau đây Can I set variables to undefined or pass undefined as an argument? giải thích sự khác biệt một cách rất chi tiết.

Tóm tắt:

Bạn chắc chắn có thể gán không xác định với nó, nhưng điều đó sẽ không xóa các biến . Chỉ có toán tử delete.property xóa thực sự xóa thứ.

xóa thực sự có nghĩa là cho các thuộc tính thay vì các biến như vậy. Trình duyệt sẽ cho phép bạn thoát khỏi biến xóa thẳng, nhưng đó là không phải là ý tưởng hay và sẽ không hoạt động ở chế độ nghiêm ngặt của Ấn bản ECMAScript. Nếu bạn muốn giải phóng một tham chiếu đến một thứ gì đó để nó có thể là được thu thập rác, sẽ có nhiều điều bình thường hơn để nói biến = null.

19

Như Mike Samuel chỉ ra trong câu trả lời của mình, một trong những cách sử dụng phổ biến nhất của xóa là khi bạn xử lý một đối tượng như một "túi tài sản" kết hợp tên với giá trị. Có một sự khác biệt hợp lý giữa "tên này bây giờ được ánh xạ tới một số giá trị không có thật" và "tên này không được ánh xạ ở tất cả". "xóa" đạt được sau này.

Đó là tất cả được hiểu một cách hợp lý. Tôi nghĩ rằng tôi có thể thêm một lưu ý lịch sử thú vị liên quan đến các công cụ JScript 1.0 đến 5.0.

Trong những triển khai gốc của Microsoft của JScript, chúng tôi đã sử dụng các đối tượng IDispatch kiểu tự động hóa OLE để triển khai đối tượng expando. IDispatch của khóa học hoạt động bằng cách liên kết một tên với một "id công văn", mà chỉ đơn giản là một số nguyên. Để gọi động, trước tiên bạn yêu cầu đối tượng gửi để cung cấp cho bạn ID công văn được liên kết với tên và sau đó bạn nói "bây giờ gọi phương thức được liên kết với ID này, được cung cấp các đối số".

Đó là tất cả tốt và tốt. Nhưng một trong những yêu cầu của hợp đồng IDispatch là ánh xạ từ tên đến ID công văn là ổn định trong toàn bộ vòng đời của đối tượng. Vì vậy, nếu ai đó nói "thêm thuộc tính Foo cho đối tượng này", thì chúng tôi có thể quyết định rằng thuộc tính Foo được liên kết với công cụ nhận dạng 0x1234 trong đối tượng đó. Từ thời điểm đó trở đi, mỗi lần đối tượng được yêu cầu nhập mã nhận dạng của "Foo", nó phải trả về 0x1234, ngay cả khi Foo bị xóa và sau đó được thêm lại. Điều này cho phép người gọi duy trì bộ nhớ cache nhanh của các cặp tên/phân phối thay vì luôn phải hỏi đối tượng trên mọi yêu cầu.

Kết quả thực tế về điều đó là "xóa" không theo bất kỳ cách nào làm giảm gánh nặng bộ nhớ trên đối tượng trong việc thực hiện đó! Khi bạn xóa một thuộc tính (trong triển khai ban đầu), chúng ta phải thêm một chút vào đối tượng đánh dấu công cụ nhận dạng đã xóa, nhưng chúng ta phải giữ lại tất cả thông tin về việc ghép cặp tên/id trong trường hợp tên đó quay trở lại. Thêm một số lượng lớn các thuộc tính vào một đối tượng và sau đó xóa tất cả chúng không thu nhỏ đối tượng trong bộ nhớ.

Công cụ JScript dĩ nhiên đã được viết lại hoàn toàn kể từ thời gian của tôi (ngoại trừ, tôi tin, trình phân tích cú pháp và lexer) vì vậy tôi không biết liệu động cơ vẫn còn có sự không bình thường này. Nó sẽ là thú vị để tìm hiểu.

2

Các câu trả lời khác giải thích động lực đằng sau từ khóa delete. Tôi muốn thêm rằng kể từ năm 2017, trình duyệt làm chia sẻ bộ nhớ cả khi xóa thuộc tính và khi đặt thuộc tính thành không xác định.

Hãy xem xét ví dụ này (source of roughSizeOfObject()):

> var obj = {a:42,b:"b"}; roughSizeOfObject(obj) 
26 
> obj.a = undefined; roughSizeOfObject(obj) 
18 
> delete obj.a; roughSizeOfObject(obj) 
10 
> obj.b = undefined; roughSizeOfObject(obj) 
8 
> delete obj.b; roughSizeOfObject(obj) 
0 

Ví dụ đến từ Chrome 61 (64-bit) giao diện điều khiển (lưu ý rằng tất cả các nhân vật trong String được nội mã hóa như integer unsigned 16-bit).

Các vấn đề liên quan