想瞭解delete的機制緣起一個現象,我無法解釋,也無法理解。
首先看一下下面這個例子:
var x = 1;
delete x; //false
然後我又執行瞭一次:
y = 2;
delete y; //true
看到上面的結果,我比較吃驚,為什麼同樣是刪除,區別怎麼這麼大呢?進而我想學習和瞭解一下JS delete的機制。
在MDN(Mozilla Developer Network)上看到下面一個例子
x = 42; // creates the property x on the global object
var y = 43; // declares a new variable, y
myobj = {
h: 4,
k: 5
};
delete x; // returns true (x is a property of the global object and can be deleted)
delete y; // returns false (delete doesn't affect variable names)
delete Math.PI; // returns false (delete doesn't affect certain predefined properties)
delete myobj.h; // returns true (user-defined properties can be deleted)
delete myobj; // returns true (myobj is a property of the global object, not a variable, so it can be deleted)
我們可以看出,delete元算符執行的結果要麼是true,要麼是false。那麼什麼時候返回true,什麼時間返回false呢?
簡單的總結瞭一句話:隻要可以被刪除,就會返回true(看起來像是一句廢話,可能實際上也是一句廢話)
此時我們要討論的就是什麼時候才能被刪除?
總結上面的例子我們發現:
1.在global object上的屬性可以被刪除;
2.聲明的變量不能被刪除
3.未聲明的全局變量可以被刪除
4.內置對象的屬性不能被刪除
為什麼會有這個結果?
要想知道原理,首先瞭解兩個概念:上下文和屬性特性。
1.上下文
我們知道每條語句在執行的時候,他都會處在一個環境中,這個環境就是這條語句的上下文環境。當一個函數執行時,會進入函數代碼執行的上下文;全局代碼執行時,會進入全局代碼執行的上下文。每個執行上下文中都會存在一個內部的可變對象(variable object),當進入這個環境的時候,會實例化這個可變對象,然後聲明的變量和方法,都會作為這個可變對象的屬性。那麼在上述所說到的兩個執行環境就會實例化兩種對象,全局對象(global object)和激活對象(activation object)。
2.屬性特性
ECMAScript5中可以查詢,設置這些特性。我們將存取器屬性的getter,setter方法看成是屬性的特性,同理,可以把數據屬性的值看做屬性的特性。所以可認為一個屬性包含一個名字和4個特性(見下表)。 ECMACScript5定義瞭一個名為“屬性描述符”的對象。這個對象代表那4個特性。通過Object.getOwnPropertyDescriptor(object, propertyname)可以獲得某個對象特定屬性的屬性描述符。
特性名
說明
Configurable
設置屬性是否可配置,即能否更改(包括名值)或者刪除(delect)它,能否修改屬性特性等等
Enumerable
設置屬性是否可以枚舉,即能否通過for-in循環返回
Writable
是否可寫
Value
就是屬性值,對象在讀取屬性值時就是從這個位置讀取的.
這裡delete會涉及到Configurable特性。可通過上述方法getOwnPropertyDescriptor簡單判斷是否可以delete。開始說的兩個例子的結果如下:
var x = 1;
Object.getOwnPropertyDescriptor(window, 'x'); //configurable= false
delete x; //false
y = 2;
Object.getOwnPropertyDescriptor(window, 'y'); //configurable= true
delete y; //true
這裡還需要交代的是,屬性的特性是在創建的時候就確定的,賦值並不能改變它的特性,
function sum() {}
sum = 1;
Object.getOwnPropertyDescriptor(window, 'sum'); //configurable= false
delete sum; //false
但是可以通過這個方法定義的特性值Object.defineProperties(object, descriptors),
Object.defineProperties(window, {sum1:{value:1,configurable:true}});
Object.getOwnPropertyDescriptor(window, 'sum'); //configurable= true
delete sum1; //true
Object.defineProperties(window, {sum2:{value:1,configurable:false}});
Object.getOwnPropertyDescriptor(window, 'sum'); //configurable= false
delete sum2; //false
總結一下delete不能刪除屬性:
1.聲明的變量(變量、函數、函數參數)不能刪除;如:var x=1;
2.內置對象的屬性不能刪除;如:Math.PI
3.定義的變量屬性的configurable值為false的,不能刪除。