一、變量
說到javascript中的delete操作符,還是首先要搞清楚javascript中的變量和屬性之間的關系。
javascript中,變量和對象屬性關系非常微妙,甚至可以很多時候會被等同起來,因為 javascript 在執行腳本之前會創建一個global對象,在浏覽器中就是window對象,所有的全局變量都是這個global對象的屬性,執行函數時也會創建一個activation對象,所有的局部變量都是這個activation對象的屬性。這些可以大家可以去了解一下javascript作用域和閉包。
復制代碼 代碼如下:
//原型中聲明的屬性無法被刪除
var global = 1;
this.global; // 1, 可以通過this來訪問global對象
this.global2 = 2;
global2; // 12
function foo() {
var local = 36;
// 不過無法直接訪問activation,
// 因此無法通過 foo.local 的方式來訪問local變量
}
似乎變量就等同於對象屬性,其實不然,至少對於delete操作符來說還是不一樣的。我的理解是變量聲明是必須通過 var 語句來完成的,未通過var 語句聲明的全局變量都是都是window對象的屬性。這樣就很容易的理解變量和對象屬性的關系了。
二、delete操作符
delete操作符是用來刪除對象屬性的。對於引用類型的值,它也是刪除對象屬性的本身,不會刪除屬性指向的對象。如果有疑問可以看看基本類型和引用類型的值,或者測試下面的代碼:
復制代碼 代碼如下:
var o = {};
var a = { x: 10 };
o.a = a;
delete o.a; // o.a屬性被刪除
console.log(o.a); // undefined
console.log(a.x); // 10, 因為{ x: 10 } 對象依然被 a 引用,所以不會被回收
另外,delete o.x 也可以寫作 delete o["x"],兩者效果相同。
三、變量是不能刪除的
通過var聲明的變量和通過function聲明的函數擁有dontdelete特性,是不能被刪除。未通過var聲明的全局變量(全局對象的屬性)
復制代碼 代碼如下:
var global = {
a: 123,
b: {
c: 1345
}
};
delete global; //無效
console.log(global)
obj = {
a: 123
};
delete obj; // 刪除obj全局變量,window對象的obj屬性
console.log(obj);//obj is not defined
四、原型中聲明的屬性和對象自帶的屬性無法被刪除
原型prototype中聲明的屬性和對象自帶的屬性(其實這些屬性也是在原型prototype中的)可以認為是帶有dontdelete的特性的,無法被刪除。例如
復制代碼 代碼如下:
//原型中聲明的屬性無法被刪除
function obj() {
this.x = 1;
}
obj.prototype.x = 2;
var o = new obj();
console.log(o.x); // 1, 構造函數中定義的o.x
delete o.x;
console.log(o.x); // 2, prototype中定義的o.x,即使再次執行delete o.x也不會被刪除
//對象自帶的屬性無法被刪除
var strings = "123456";
console.log(strings.length);//6
delete strings.length;
console.log(strings.length);//依然是6
五、eval語句下的幾個例外
eval執行的代碼中,通過var聲明的變量雖然與正常的var聲明變量同屬於global對象,但它們不具有dontdelete特性,能被刪除。但是eval的代碼中的函數內通過var定義的變量具有dontdelete,不能被刪除。
復制代碼 代碼如下:eval("var x = 42;");
x; // => 42
delete x;
x; // => referenceerror: x is not defined
eval("function f() { return 12; }");
f(); // => 12
delete f;
f(); // => referenceerror: f is not defined
//eval執行的代碼中,通過var聲明的變量雖然與正常的var聲明變量同屬於global對象,
// 但它們不具有dontdelete特性,能被刪除。
eval("(function () {" +
" var x = 42;" +
" delete x;" +
" return x;" +
"})();")
// => 42
// eval的代碼中的函數內通過var定義的變量具有dontdelete,不能被刪除。
六、delete的返回值
delete是普通運算符,會返回true或false。當被delete的對象的屬性存在並且擁有dontdelete時 返回false,否則返回true。 這裡的一個特點就是,對象屬性不存在時也返回true,所以返回值並非完全等同於刪除成功與否。
復制代碼 代碼如下:
function c() {
this.x = 42;
}
c.prototype.y = 12;
var o = new c();
delete o.x; // true
o.x; // undefined
"x" in o; // false
// o.x存在並且沒有dontdelete,返回true
delete o.y; // true
o.y; // 12
// o自身沒有o.y屬性,所以返回true
// 從這裡也可以看到prototype鏈的存在,對象自身屬性和prototype屬性是不同的
delete o; // false
// global.o擁有dontdelete特性所以返回false
delete undefinedproperty; // true
// global沒有名為undefinedproperty的屬性因此返回true
delete 42; // true
// 42不是屬性所以返回true。有的實現會拋出異常(違反ecmascript標准)
var x = 24;
delete x++; // true
x; // 25
// 被刪除的是x++的返回值(24),不是屬性,所以返回true