JS中的可枚舉屬性與不可枚舉屬性


 什么是枚舉?枚舉是指對象中的屬性是否可以遍歷出來,再簡單點說就是屬性是否可以以列舉出來。

 一、怎么判斷屬性是否可枚舉

       在JavaScript中,對象的屬性分為可枚舉和不可枚舉之分,它們是由屬性的enumerable值決定的。可枚舉性決定了這個屬性能否被for…in查找遍歷到。

       js中的基本包裝類型的原型屬性是不可枚舉的,比如Object,Array,Number等

       這是一個例子:

var num = new Number();
for(var pro in num) {
   console.log("num." + pro + " = " + num[pro]);
}
//此處沒有輸出

它的輸出結果是空的,因為Number中的內置屬性是不可枚舉的,所以不能被 for ... in 訪問到 

      每個對象都有propertyIsEnumerable()方法,這個方法可以判斷出指定的屬性是否可枚舉。

       用法:     
       obj.propertyIsEnumerable("屬性名");

function Person(){
    this.name = "我是實例屬性"
    this.age = 19;  
}
var p = new Person();
console.log(p.propertyIsEnumerable("name")); //true
 
Person.prototype.prop = "我是原型屬性" //添加一個原型屬性
console.log(p.propertyIsEnumerable("prop")); //false prop是繼承自原型上的屬性,所以返回的是false
 
for(var k in p){
  console.log(k+","+p[k]);//name,我是實例屬性  age,19  prop,我是原型屬性
}

    從中也可以發現,如果是對象的原型鏈中的屬性,不管是否枚舉都會返回false。
    但是 for ...in 仍然可以讀出原型鏈中的可枚舉屬性 

二、枚舉屬性的作用

 枚舉屬性主要會影響幾個方法

ES5中:
    for...in                         //只遍歷對象自身的和繼承的可枚舉的屬性
    Object.keys()             //返回對象自身的所有可枚舉的屬性的鍵名
    JSON.stringify           //JSON.stringify() 方法用於將 JavaScript 值轉換為 JSON 字符串。
 
ES6中:
    Object.assign()          //會忽略enumerable為false的屬性,只拷貝對象自身的可枚舉的屬性。

    可以看出來這些都是可以遍歷對象的方法,而這四個操作中只有for...in中會返回繼承的屬性

    先看一個例子,創建一個"xsy"對象:

function Person(){
    this.name = "XSY"
};
Person.prototype = {
    constructor: Person,
    job:"student",
};
 
var xsy = new Person();
Object.defineProperty(xsy, "sex",{
    value:"female",
    enumerable:false
});

      這里用defineProperty方法定義了一個叫"sex"的不可枚舉屬性

然后可以開始驗證了:

a.  for...in

for(var pro in xsy){
    console.log("xsy." + pro+ " = " + xsy[pro]);
}

     輸出的結果如下,可以發現 對象中聲明的屬性,原型鏈上綁定的屬性成功輸出了,而不可枚舉屬性“sex”沒有輸出。

 

 

  b.  Object.keys()

console.log(Object.keys(xsy));

 從輸出結果可以發現,這里只輸出了對象聲明的可枚舉屬性,但是沒有輸出原型鏈中的可枚舉屬性

c. JSON.stringify

console.log(JSON.stringify(xsy));

這里的輸出也和上面一樣,結果中只有對象中的可枚舉屬性沒有原型鏈中的。

 

 

        從上面這些操作中大概可以明白了,可枚舉性決定了這個屬性能否被for…in查找遍歷到。所以可枚舉與否都是開發者自己定義的,
可以通過Object.defineProperty()方法。

三、設置可枚舉屬性

    其實在上面的例子中已經使用到了設置enumerable的方法:Object.defineProperty()

var person = {
    name:'xiao',
    age: '18',
    sex: 'boy'
}
 
Object.defineProperty(person,'age',{
    enumerable:true,//可以被枚舉
});
Object.defineProperty(person,'sex',{
    enumerable:false,//不可以被枚舉
})
 
for(var k in person){
    console.log(person[k])//a,可以被枚舉
}
//18
//xiao

      從上面可以看出:
     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. 案例:
  4. 1)用戶自定義對象和引擎內置對象的區別
Math.propertyIsEnumerable('random');   // 返回 false
Object.propertyIsEnumerable('constructor');    // 返回 false
var num = new Number();
for(var pro in num) {
    console.log("num." + pro + " = " + num[pro]);
}//輸出空
  1. 這說明了開發者自定義的屬性在一般情況下時可以枚舉的,但是內置的對象Math和基本包裝類型里的屬性是不可枚舉的,如Object, Array, Number等;其實,propertyIsEnumerable方法只對對象自身的屬性(對象自身添加的、構造函數實例化的)有效,對原型上的、繼承來的屬性都無效。

五、總結

  1.  for...in循環是 遍歷對象的每一個可枚舉屬性,包括原型鏈上面的可枚舉屬性;
  2. 而Object.keys()只是遍歷自身的可枚舉屬性,不可以遍歷原型鏈上的可枚舉屬性. 這是for...in和Object.keys()的主要區別;
  3. Object.getOwnPropertyNames()則是遍歷自身所有屬性(不論是否是可枚舉的),不包括原型鏈上面的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM