js for in 和for區別詳解

在JavaScript中,對象的屬性分爲可枚舉和不可枚舉之分,它們是由屬性的enumerable值決定的,我們應該清楚什麼是枚舉屬性,什麼是不可枚舉屬性?

1.怎麼判斷屬性是否可枚舉

一.propertyIsEnumerable方法
每個對象都有一個 propertyIsEnumerable 方法。此方法可以確定對象中指定的屬性是否可以被枚舉,但是通過原型鏈繼承的屬性除外。如果對象沒有指定的屬性,則此方法返回 false,propertyIsEnumerable() 方法返回一個布爾值,表示指定的屬性是否可枚舉。

var  arr = [1,2,3,4];
 Array.prototype.method  = function(){
     console.log("method");
 };
 console.log(arr.propertyIsEnumerable(0));//true  arr[0]===1
 console.log(Array.prototype.propertyIsEnumerable("method"));//true
 console.log(Array.prototype.propertyIsEnumerable("concat"));//flase

二.Object.getOwnPropertyDescriptor方法
返回指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不需要從原型鏈上進行查找的屬性)

var  arr = [1,2,3,4];
Array.prototype.method  = function(){
 console.log("method");
};
console.log(Object.getOwnPropertyDescriptor(arr,0)); //{value: 1, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(Array.prototype,"method"));//{value: ƒ, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(Array.prototype,"split"));//{value: ƒ, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(Array.prototype,"concat"));//{value: ƒ, writable: true, enumerable: false, configurable: true}

主要是enumerable這個屬性來決定是否可枚舉!
1.value:代表該屬性的值
2.writable :當且僅當屬性的值可以被改變時爲true。(僅針對數據屬性描述有效)
3.enumerable:當且僅當指定對象的屬性可以被枚舉出時,爲 true
4.configurable:當且僅當指定對象的屬性描述可以被改變或者屬性可被刪除時,爲true。

2.修改是否可枚舉

Object.defineProperty方法(直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,並返回此對象)

var  arr = [1,2,3,4];
Array.prototype.method  = function(){
    console.log("method");
};
Object.defineProperty(Array.prototype,"method",{
   enumerable:false
})
console.log(Array.prototype.propertyIsEnumerable("method"));//false
3.對比循環

有了上面的瞭解,我們再來說說 for in 和for循環的吧

一.for…in 循環只遍歷可枚舉屬性(包括它的原型鏈上的可枚舉屬性)
它會把原型鏈上的屬性遍歷出來,不過你可以通過hasOwnProperty過濾掉!for循環不會遍歷出原型鏈上的屬性!

 var  arr = [1,2,3,4];
 Array.prototype.method  = function(){
     console.log("method");
 };
 for(var k  in arr){
     console.log(arr[k]);//1,2,3,4,ƒ (){console.log("method");}
 };
 for(var k  in arr){
     if(arr.hasOwnProperty(k)){
        console.log(arr[k]);//1,2,3,4
     };
 };
 //看下for循環
for(var i =0 ;i<arr.length;i++){
    console.log(arr[i]);//1,2,3,4
}

二.for…in和for遍歷數組時下標類型不一樣

var  arr = [1,2,3,4];
  for(var k  in arr){
      if(arr.hasOwnProperty(k)){
         console.log(typeof k);//string
      };
  };

  for(var i =0 ;i<arr.length;i++){
      console.log(typeof i); //number
  }

for in 的下標是string,for下標是number,這點比較容易忽略!
三.對稀疏數組的執行效率
什麼是稀疏呢?稀疏也就是說,數組中的元素之間可以有空隙!

var  arr = [1,2,3,4];
arr.length =10;
console.log(arr); //這個就是稀疏數組 [1, 2, 3, 4, empty × 6]

再來看下執行效率

var arr = [1, 2, 3, 4];
arr.length = 10;
console.log(arr);
for (var k in arr) {
    if (arr.hasOwnProperty(k)) {
        console.log(k); //0,1,2,3
    };
};

for (var i = 0; i < arr.length; i++) {
    console.log(i); //0,1,2,3,4,5,6,7,8,9
}

我們知道如果將其length屬性設置爲大於數組項數的值,其實後面多出的每一項都會是undefined值,for in 只執行4次,而for循環執行了10次,

console.log(arr.propertyIsEnumerable(3));//true
console.log(arr.propertyIsEnumerable(4));//false
console.log(arr.propertyIsEnumerable(5));//false
console.log(arr.propertyIsEnumerable(6));//false
console.log(arr.propertyIsEnumerable(7));//false
console.log(arr.propertyIsEnumerable(8));//false
console.log(arr.propertyIsEnumerable(9));//false
console.log(arr.propertyIsEnumerable(10));//false

這個就是爲什麼for in 只執行4次,因爲for in 對於不存在的項是不會被枚舉出來的!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章