JavaScript中的delete操作符

 今天在看prototype代碼時發現了delete這個操作符
  1.         unset: function(key) {
  2.             var value = this._object[key];
  3.             delete this._object[key];
  4.             return value;
  5.         }
查了一下手冊,

delete 運算符
從對象中刪除一個屬性,或從數組中刪除一個元素。
delete expression
expression 參數是一個有效的 JScript 表達式,通常是一個屬性名或數組元素。
說明
如果 expression 的結果是一個對象,且在 expression 中指定的屬性存在,而該對象又不允許它被刪除,則返回
false
在所有其他情況下,返回
true。 


看到“從數組中刪除一個元素”感覺不錯,可ff裏試了一下,似乎只能刪除那個元素的值,而不是元素本身。不過從對象中刪除一個屬性是可以的。

又google了一下,發現有一篇文章講得很詳細,轉載過來以免忘記:


剛剛看到一篇好文(原文鏈接),對Javascript中的delete操作符分析得很透徹。在這裏簡單地介紹一下內容。

雖然是一個小小的delete操作符,其行爲卻異常複雜。

  • Javascript的變量
  • delete操作符刪除的對象
  • 對變量執行delete的情況
  • 能刪除的屬性和不能刪除的屬性
  • 能刪除的變量和不能刪除的變量
  • delete的返回值

Javascript的變量

實際上Javascript中,變量 = 對象屬性,這是因爲 Javascript 在執行腳本之前會創建一個Global對象,所有的全局變量都是這個Global對象的屬性,執行函數時也會創建一個Activation對象,所有的局部變量都是這個Activation對象的屬性。如下例:

  1. var global = 42;
  2. this.global;    // 42, 可以通過this來訪問Global對象
  3. this.global2 = 12;
  4. global2;        // 12
  5. function foo() {
  6.   var local = 36;
  7.   // 不過無法直接訪問Activation,
  8.   // 因此無法通過 foo.local 的方式來訪問local變量
  9. }

delete操作符刪除的對象

C++中也有delete操作符,它刪除的是指針所指向的對象。例如:

  1. // C++
  2. class Object {
  3. public:
  4.   Object *x;
  5. }
  6. Object o;
  7. o.x = new Object();
  8. delete o.x;     // 上一行new的Object對象將被釋放

但Javascript的delete與C++不同,它不會刪除o.x指向的對象,而是刪除o.x屬性本身

  1. // Javascript
  2. var o = {};
  3. o.x = new Object();
  4. delete o.x;     // 上一行new的Object對象依然存在
  5. o.x;             // undefined,o的名爲x的屬性被刪除了

在實際的Javascript中,delete o.x之後,Object對象會由於失去了引用而被垃圾回收,所以delete o.x也就“相當於”刪除了o.x所指向的對象,但這個動作並不是ECMAScript標準,也就是說,即使某個實現完全不刪除Object對象,也不算是違反ECMAScript標準。

“刪除屬性而不是刪除對象”這一點,可以通過以下的代碼來確認。

  1. var o = {};
  2. var a = { x: 10 };
  3. o.a = a;
  4. delete o.a;    // o.a屬性被刪除
  5. o.a;            // undefined
  6. a.x;            // 10, 因爲{ x: 10 } 對象依然被 a 引用,所以不會被回收

另外,delete o.x 也可以寫作 delete o["x"],兩者效果相同。

對變量執行delete的情況

由於變量也是 Global 或者是 Activation 對象的屬性,所以對變量的delete操作也是同樣的結果。

  1. var global = 42;
  2. delete global;     // 刪除Global.global
  3. function foo() {
  4.   var local = 36;
  5.   delete local;    // 刪除Activation.local
  6. }

能刪除的屬性和不能刪除的屬性

並不是所有的屬性都能被delete。例如,prototype中聲明的屬性就無法被delete:

  1. function C() { this.x = 42; }
  2. C.prototype.x = 12;
  3. var o = new C();
  4. o.x;     // 42, 構造函數中定義的o.x
  5. delete o.x;
  6. o.x;     // 12,  prototype中定義的o.x,即使再次執行delete o.x也不會被刪除

對象的預定義屬性也無法刪除。 可以認爲這類屬性帶有DontDelete的特性。

  1. var re = /abc/i;
  2. delete re.ignoreCase;
  3. re.ignoreCase; // true, ignoreCase無法刪除

能刪除的變量和不能刪除的變量

通過var聲明的變量和通過function聲明的函數擁有DontDelete特性,無法被刪除。

  1. var x = 36;
  2. delete x;
  3. x;     // 36, x沒有被刪除
  4. y = 12;
  5. delete y;
  6. y;     // undefined
  7. function foo() { return 42; }
  8. delete foo;
  9. foo();  // 42

但是有一點例外,就是通過 eval 執行的代碼中,通過var聲明的變量雖然與正常的var聲明變量同屬於Global對象,但它們不具有DontDelete特性,能被刪除。

  1. eval("var x = 36;");
  2. x;     // 42
  3. delete x;
  4. x;     // undefined

但是這也有一點例外,eval的代碼中的函數內通過var定義的變量具有DontDelete,不能被刪除

  1. eval("(function() { var x = 42; delete x; return x; })();");
  2. // 返回 42

delete的返回值

delete是普通運算符,會返回true或false。規則爲:當被delete的對象的屬性存在並且擁有DontDelete時返回false,否則返回true。這裏的一個特點就是,對象屬性不存在時也返回true,所以返回值並非完全等同於刪除成功與否。

  1. function C() { this.x = 42; }
  2. C.prototype.y = 12;
  3. var o = new C();
  4. delete o.x; // true
  5. o.x;        // undefined
  6. "x" in o;   // false
  7. // o.x存在並且沒有DontDelete,返回true
  8. delete o.y; // true
  9. o.y;        // 12
  10. // o自身沒有o.y屬性,所以返回true
  11. // 從這裏也可以看到prototype鏈的存在,對象自身屬性和prototype屬性是不同的
  12. delete o;   // false
  13. // Global.o擁有DontDelete特性所以返回false
  14. delete undefinedProperty;  // true
  15. // Global沒有名爲undefinedProperty的屬性因此返回true
  16. delete 42;  // true
  17. // 42不是屬性所以返回true。有的實現會拋出異常(違反ECMAScript標準)
  18. var x = 24;
  19. delete x++;  // true
  20. x;           // 25
  21. // 被刪除的是x++的返回值(24),不是屬性,所以返回true




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章