1. 程式人生 > >可列舉與不可列舉

可列舉與不可列舉

先把總結寫在這裡:

  1. JavaScript物件的屬性可分為可列舉和不可列舉,它是由屬性的enumeration值決定的,true為可列舉,false為不可列舉
  2. js中原型屬性一般是不可列舉的,而自己定義的屬性一般是可列舉的
  3. 可以通過propertylsEnumerable()方法判斷該屬性是否可列舉
  4. 屬性的列舉性會影響以下三個函式的結果
    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() 語法

  1. 語法:obj.propertyIsEnumerable(prop)
  2. 描述:每個物件都有一個propertyIsEnumerable方法。此方法可以確定物件中指定的屬性是否可列舉,返回一個布林值。但該方法對通過原型鏈繼承的屬性無效(原型鏈繼承的屬性是否可列舉不能用該方法來判斷)
  3. 案例:
    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,所以該方法對其無效。