上節我們討論了對象的定義和對象的創建,知道了函數也是對象,知道了對象都是由函數創建的,知道了對象的原型和函數的原型屬性的關係。這節說一下關於對象屬性的操作,下節就可以切入正題了。 屬性刪除 delete操作符刪除一個屬性值後會返回true,第5行也返回true是因為person.age已經是個und ...
上節我們討論了對象的定義和對象的創建,知道了函數也是對象,知道了對象都是由函數創建的,知道了對象的原型和函數的原型屬性的關係。這節說一下關於對象屬性的操作,下節就可以切入正題了。
屬性刪除
1 var person = {age : 28, title : 'fe'}; 2 delete person.age; // true 3 delete person['title']; // true 4 person.age; // undefined 5 delete person.age; // true 6 7 delete Object.prototype; // false, 8 9 var descriptor = Object.getOwnPropertyDescriptor(Object, 'prototype'); 10 console.log(descriptor) //Object {value: Object, writable: false, enumerable: false, configurable: false}
delete操作符刪除一個屬性值後會返回true,第5行也返回true是因為person.age已經是個undefined,所以仍然會返回一個true,第7行刪除Object的prototype屬性返回了一個false,我們可以通過第9行Object.getOwnPropertyDescriptor()方法查看一下Object.prototype的特性,configurable屬性值為false(不可配置),因此返回false。
屬性檢測
1 var cat = new Object(); 2 cat.legs=4; 3 'legs' in cat; //true 4 'toString' in cat; //false 5 cat.propertyIsEnumerable('legs'); // true 6 cat.propertyIsEnumerable('toString'); // false
使用propertyIsEnumerable()可以判斷一個屬性是不是可枚舉的,如果想設置一個屬性的特性是不是可枚舉的怎麼辦呢,看下邊:
1 Object.defineProperty(cat, 'price', {enumerable : true, value : 1000}); 2 cat.propertyIsEnumerable('price'); // true 3 cat.hasOwnProperty('price'); // true
使用Object.defineProperty()方法可以設置屬性的特性值,如上我們可以把可枚舉的特性設置為true或false。
屬性枚舉
in關鍵字可以判斷屬性是否存在,for in語句則不能枚舉enumerable 值為false的屬性,如:
1 var o={a:'1',b:'2'} 2 Object.defineProperty(o,'c',{ 3 Enumberable:false 4 }); 5 console.log('c' in o) //true 6 var key; 7 for(key in o){ 8 console.log(key) //a,b 9 }
get/set方法
get/set方法是另一種進行屬性操作的方式,如:
1 var man = { 2 name : 'James', 3 get age() { 4 return new Date().getFullYear() - 1988; 5 }, 6 set age(val) { 7 console.log('Age can\'t be set to ' + val); 8 } 9 } 10 console.log(man.age); // 27 11 man.age = 100; // Age can't be set to 100 12 console.log(man.age); // 27
取一個屬性值age時會觸發get方法,給age賦值時觸發set方法,賦值成不成功取決於set方法內部是否會對屬性進行修改。
屬性標簽
1 Object.getOwnPropertyDescriptor({pro : true}, 'pro'); 2 // Object {value: true, writable: true, enumerable: true, configurable: true} 3 Object.getOwnPropertyDescriptor({pro : true}, 'a'); // undefined
前邊提到過這個方法,可以返回一個屬性特性描述的對象,分別有4個屬性,value表示屬性值,writable表示屬性值是否可寫,enumberable表示屬性值是否可被枚舉,configurable表示屬性是否可被用其他方式進行操作(如delete操作符)。
1 Object.defineProperties(person, { 2 title : {value : 'fe', enumerable : true}, 3 corp : {value : 'BABA', enumerable : true}, 4 salary : {value : 50000, enumerable : true, writable : true}, 5 luck : { 6 get : function() { 7 return Math.random() > 0.5 ? 'good' : 'bad'; 8 } 9 }, 10 promote : { 11 set : function (level) { 12 this.salary *= 1 + level * 0.1; 13 } 14 } 15 }); 16 17 Object.getOwnPropertyDescriptor(person, 'salary'); 18 // Object {value: 50000, writable: true, enumerable: true, configurable: false} 19 Object.getOwnPropertyDescriptor(person, 'corp'); 20 // Object {value: "BABA", writable: false, enumerable: true, configurable: false} 21 person.salary; // 50000 22 person.promote = 2; 23 person.salary; // 60000
使用Object.defineProperties()方法可以定義多個屬性的值,而且get,set方法可以不針對同一個屬性進行操作,這個例子可以系統包含整個知識點。所有的屬性特性值不輸入均預設為false。
下圖提供了configurable和writable不同情況下的操作影響:
可以看出這兩個屬性值均為true時我們基本可以做任何操作,屬性都為false時我們都做不了,其他情況就不再贅述了。
對象標簽
對象標簽有三個:__proto__,__class__,__extensible__,__proto__下節討論。
__class__屬性無法直接訪問,我們只能藉助於Object.toString方法來簡介訪問到,如下:
1 var toString = Object.prototype.toString; 2 function getType(o){return toString.call(o).slice(8,-1);}; 3 4 toString.call(null); // "[object Null]" 5 getType(null); // "Null" 6 getType(undefined); // "Undefined" 7 getType(1); // "Number" 8 getType(new Number(1)); // "Number" 9 typeof new Number(1); // "object" 10 getType(true); // "Boolean" 11 getType(new Boolean(true)); // "Boolean"
__extensible__標簽表示對象是否可擴展,即該對象是否可以繼續添加屬性,看下邊代碼:
1 var obj = {x : 1, y : 2}; 2 Object.isExtensible(obj); // true 3 Object.preventExtensions(obj); 4 Object.isExtensible(obj); // false 5 obj.z = 1; 6 obj.z; // undefined, add new property failed 7 Object.getOwnPropertyDescriptor(obj, 'x'); 8 // Object {value: 1, writable: true, enumerable: true, configurable: true} 9 10 Object.seal(obj); 11 Object.getOwnPropertyDescriptor(obj, 'x'); 12 // Object {value: 1, writable: true, enumerable: true, configurable: false} 13 Object.isSealed(obj); // true 14 15 Object.freeze(obj); 16 Object.getOwnPropertyDescriptor(obj, 'x'); 17 // Object {value: 1, writable: false, enumerable: true, configurable: false} 18 Object.isFrozen(obj); // true 19 20 // [caution] not affects prototype chain!!!
第2行代碼使用Object.isExtensible()方法,我們可以檢測是否可以進行對象屬性擴展,然後Object.preventExtensions()方法,我們可以設置對象不能進行擴展,但該對象屬性標簽的原始值仍然保持不變,如第7行;
使用seal()方法會將該對象的所有屬性標簽的configurable值設置為false,而freeze()方法會將該對象的所有屬性標簽的configurable和writable值均設置為false。
下節開始討論__proto__原型鏈和繼承相關內容。