本文主要和大家分享js中delete操作符與內部屬性實例詳解,在講解Configurable之前,我們先來看一道面試題:
a = 1;console.log( window.a ); // 1console.log( delete window.a ); // trueconsole.log( window.a ); // undefinedvar b = 2;console.log( window.b ); // 2console.log( delete window.b ); // falseconsole.log( window.b ); // 2
從上面的這題可以看出兩個的差異:在沒有使用var宣告變數時,使用delete關鍵字是可以進行刪除的,再次取得時值就是undefined了;在使用var宣告的變量,使用delete是不能刪除的,再取得時值依然是2 。
使用delete刪除變數或屬性時,刪除成功回傳true,否則回傳false。如同上面的例子中,當delete無法刪除變數a時,則回傳false;而delete能成功刪除變數b,則傳回true。
除了上述的兩種情況,還有其他的各種常用變數也有能被delete刪除的,也有不能刪除的。我們先不管delete這些變數時,為什麼會產生這樣的結果,這裡只看他的回傳值:
刪除delete數組中其中的一個元素:
// 使用for~in是循环不到的,直接忽略到该元素 // 使用for()可以得到该元素,但是值是undefinedvar arr = [1, 2, 3, 4];console.log( arr ); // [1, 2, 3, 4]console.log( delete arr[2] ); // true,删除成功console.log( arr ); // [1, 2, undefined, 4]
刪除function類型的變數:
// chrome 不能删除;火狐可以删除function func(){ } console.log( func );console.log( delete func ); console.log( func );
刪除function.length,該length是獲取形參的個數:
function func1(a, b){ }console.log( func1.length ); // 2console.log( delete func1.length ); // true,删除成功console.log( func1.length ); // 0
刪除常用變數:
console.log( delete NaN ); // false,删除失败console.log( delete undefined ); // falseconsole.log( delete Infinity ); // falseconsole.log( delete null ); // true,删除成功
刪除prototype,而不是刪除prototype上的屬性:
function Person(){ } Person.prototype.name = "蚊子";console.log( delete Person.prototype ); // false,无法删除console.log( delete Object.prototype ); // false
刪除數組和字串的length時:
var arr = [1, 2, 3, 4];console.log( arr.length ); // 4console.log( delete arr.length ); // false,删除失败console.log( arr.length ); // 4var str = 'abcdefg';console.log( str.length ); // 7console.log( delete str.length ); // false,删除失败console.log( str.length ); // 7
刪除obj中的屬性時:
var obj = {name:'wenzi', age:25};console.log( obj.name ); // wenziconsole.log( delete obj.name ); // true,删除成功console.log( obj.name ); // undefinedconsole.log( obj ); // { age:25 }
刪除實例物件中的屬性時,從以下的輸出結果可以看出,使用delete刪除屬性時,刪除的只是實例物件本身的屬性,而不能刪除prototype上的屬性,即使再刪一次也是刪除掉不的;若要刪除prototype上的屬性的屬性或方法,只能是:delete Person.prototype.name:
function Person(){ this.name = 'wenzi'; } Person.prototype.name = '蚊子';var student = new Person();console.log( student.name ); // wenziconsole.log( delete student.name ); // true,删除成功console.log( student.name ); // 蚊子console.log( delete student.name ); // trueconsole.log( student.name ); // 蚊子console.log( delete Person.prototype.name ); // true,删除成功console.log( student.name ); // undefined
在上面的例子中,有的變數或屬性能夠刪除成功,而有的變數或屬性則無法進行刪除,那是什麼決定這個變數或屬性能不能被刪除。
ECMA-262第5版定義了JS物件屬性中特徵(用於JS引擎,外部無法直接存取)。 ECMAScript中有兩種屬性:資料屬性和存取器屬性。
資料屬性指包含一個資料值的位置,可在該位置讀取或寫入值,該屬性有4個供述其行為的特性:
. [[configurable]]:表示能否使用delete操作符刪除從而重新定義,或是否能修改為存取器屬性。預設為true;
. [[Enumberable]]:表示是否可透過for-in循環傳回屬性。預設true;
. [[Writable]]:表示是否可修改屬性的值。預設true;
. [[Value]]:包含該屬性的資料值。讀取/寫入都是該值。預設為undefined;如上實例物件Person定義了name屬性,其值為'wenzi',對該值的修改都反正在這個位置
要修改物件屬性的預設特徵(預設都為true ),可呼叫Object.defineProperty()方法,它接收三個參數:屬性所在對象,屬性名稱和一個描述符物件(必須是:configurable、enumberable、writable和value,可設定一個或多個值)。
如下:
var person = {};Object.defineProperty(person, 'name', { configurable: false, // 不可删除,且不能修改为访问器属性 writable: false, // 不可修改 value: 'wenzi' // name的值为wenzi});console.log( person.name); // wenziconsole.log( delete person.name ); // false,无法删除person.name = 'lily';console.log( person.name ); // wenzi
可以看出,delete及重置person.name的值都沒有生效,這就是因為呼叫defineProperty函數修改了物件屬性的特徵;值得注意的是一旦將configurable設為false,則無法再使用defineProperty將其修改為true(執行會報錯:Uncaught TypeError: Cannot redefine property: name);
它主要包括一對getter和setter函數,在讀取存取器屬性時,會呼叫getter傳回有效值;寫入存取器屬性時,呼叫setter,寫入新值;這個屬性有以下4個特徵:
. [[Configurable]]:是否可透過delete運算子刪除重新定義屬性;
. [[Numberable]]:是否可透過for-in循環尋找該屬性;
. [[Get]]:讀取屬性時自動調用,預設:undefined;
. [[Set]]:寫入屬性時自動調用,預設:undefined;
存取器屬性不能直接定義,必須使用defineProperty()來定義,如下:
var person = { _age: 18};Object.defineProperty(person, 'isAdult', { Configurable : false, get: function () { if (this._age >= 18) { return true; } else { return false; } } });console.log( person.isAdult ); // true
不過還是有一點需要額外注意一下,Object.defineProperty()方法設定屬性時,不能同時宣告存取器屬性(set和get)和資料屬性(writable或value) 。意思就是,某個屬性設定了writable或value屬性,那麼這個屬性就不能宣告get和set了,反之亦然。
如若像下面的方式进行定义,访问器属性和数据属性同时存在:
var o = {};Object.defineProperty(o, 'name', { value: 'wenzi', set: function(name) { myName = name; }, get: function() { return myName; } });
上面的代码看起来貌似是没有什么问题,但是真正执行时会报错,报错如下:
Uncaught TypeError: Invalid property. A property cannot both have accessors and be writable or have a value
对于数据属性,可以取得:configurable,enumberable,writable和value;
对于访问器属性,可以取得:configurable,enumberable,get和set。
由此我们可知:一个变量或属性是否可以被删除,是由其内部属性Configurable进行控制的,若Configurable为true,则该变量或属性可以被删除,否则不能被删除。
可是我们应该怎么获取这个Configurable值呢,总不能用delete试试能不能删除吧。有办法滴!!
ES5为我们提供了Object.getOwnPropertyDescriptor(object, property)来获取内部属性。
如:
var person = {name:'wenzi'};var desp = Object.getOwnPropertyDescriptor(person, 'name'); // person中的name属性console.log( desp ); // {value: "wenzi", writable: true, enumerable: true, configurable: true}
通过Object.getOwnPropertyDescriptor(object, property)我们能够获取到4个内部属性,configurable控制着变量或属性是否可被删除。这个例子中,person.name的configurable是true,则说明是可以被删除的:
console.log( person.name ); // wenziconsole.log( delete person.name ); // true,删除成功console.log( person.name ); // undefined
我们再回到最开始的那个面试题:
a = 1;var desp = Object.getOwnPropertyDescriptor(window, 'a');console.log( desp.configurable ); // true,可以删除var b = 2;var desp = Object.getOwnPropertyDescriptor(window, 'b');console.log( desp.configurable ); // false,不能删除
跟我们使用delete操作删除变量时产生的结果是一样的。
相关推荐:
JavaScript delete操作符应用实例_javascript技巧
以上是js中delete運算子與內部屬性實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!