可列舉與不可列舉
先把總結寫在這裡:
- JavaScript物件的屬性可分為可列舉和不可列舉,它是由屬性的enumeration值決定的,true為可列舉,false為不可列舉
- js中原型屬性一般是不可列舉的,而自己定義的屬性一般是可列舉的
- 可以通過propertylsEnumerable()方法判斷該屬性是否可列舉
- 屬性的列舉性會影響以下三個函式的結果
1)for...in //遍歷原型與例項上的所有可列舉屬性
2)Object.keys(); //只能返回物件本身具有的可列舉屬性。
3)JSON.stringify(); //只能讀取物件本身的可列舉屬性,並序列化為JSON物件。4)Object.getOwnPropertyNames() //遍歷自身所有屬性(不論是否是可列舉的),不包括原型鏈上面的.。
上面說了JavaScript物件的屬性是否可列舉是又enumeration的值決定的,那麼enumeration是什麼,它的值又是什麼時候去設定的呢?
enumeration是 Object.defineProperty()方法的一個引數,下面來看看怎麼去設定 一個屬性是否可列舉。
var person = { name:'zhou', age: '12', sex: 'girl' } Object.defineProperty(person,'age',{ enumerable:true,//可以被列舉 }); Object.defineProperty(person,'sex',{ enumerable:false,//可以被列舉 }) for(var k in person){ console.log(person[k])//a,可以被列舉 } //12 //zhou
如何設定是否可列舉-- enumerable
由上面的點可以看出:
1.Object.defineProperty(obj, prop, descriptor)方法有三個引數,每個引數各代表著
第一個:目標屬性所在的物件,
第二個:目標屬性,放在字串裡,
第三個:目標屬性的行為,放在物件裡;
2.enumerable為true表示可列舉,enumerable為false表示不可列舉;
3.開發者自定義的物件person的所有屬性都是可列舉的;
如何判斷是否可列舉-- propertyIsEnumerable
在不知情的情況下,我們如何判斷一個屬性是否可列舉呢?propertylsEnumerable()方法可以解決這個問題,對於上面的例子來看看他是怎麼用的
person.propertyIsEnumerable('sex');//false
person.propertyIsEnumerable('age');//true
propertyIsEnumerable() 語法
- 語法:obj.propertyIsEnumerable(prop)
- 描述:每個物件都有一個propertyIsEnumerable方法。此方法可以確定物件中指定的屬性是否可列舉,返回一個布林值。但該方法對通過原型鏈繼承的屬性無效(原型鏈繼承的屬性是否可列舉不能用該方法來判斷)
- 案例:
1)使用者自定義物件和引擎內建物件的區別
var o = {};
var a = [];
o.prop = 'is enumerable';
a[0] = 'is enumerable';
o.propertyIsEnumerable('prop'); // 返回 true
a.propertyIsEnumerable(0); // 返回 true
Math.propertyIsEnumerable('random'); // 返回 false
Object.propertyIsEnumerable('constructor'); // 返回 false
對於基本包裝型別的原型屬性是不可列舉的,如Object, Array, Number等
var num = new Number();
for(var pro in num) {
console.log("num." + pro + " = " + num[pro]);
}
它的輸出結果會是空。這是因為Number中內建的屬性是不可列舉的,所以不能被for…in訪問到。
說明開發者自定義的屬性在一般情況下是可列舉的,而內建特殊物件Math和基本包裝型別的原型屬性是不可列舉的,如Object, Array, Number等
2)自身屬性和繼承屬性
//建構函式
function firstConstructor() {
this.property = 'is not enumerable';
}
firstConstructor.prototype.firstMethod = function() {};
//繼承
function secondConstructor() {
this.method = function method() { return 'is enumerable'; };
}
secondConstructor.prototype = new firstConstructor;
secondConstructor.prototype.constructor = secondConstructor;
//例項
var o = new secondConstructor();
o.arbitraryProperty = 'is enumerable';
//打印出例項
console.dir(o)
我們來看看打印出來的例項物件,看看那些那些屬性是自身的,那些屬性是在原型上的
再看看for/in遍歷出來的列舉屬性的
最後來看看這些屬性在propertyIsEnumerable()上返回的值
console.log(o.propertyIsEnumerable('arbitraryProperty')); // 返回 true
console.log(o.propertyIsEnumerable('method')); // 返回 true
console.log(o.propertyIsEnumerable('prototype')); // 返回 false
console.log(o.propertyIsEnumerable('constructor')); // 返回 false
console.log(o.propertyIsEnumerable('firstMethod')); // 返回 false
說明propertyIsEnumerable方法只對物件自身的屬性(物件自身新增的、建構函式例項化的)有效,對原型上的、繼承來的屬性都無效。
例如圖二的屬性丟失可列舉的,但是在原型上的屬性propertyIsEnumerable()方法卻都返回false,所以該方法對其無效。