禁止使用for in 遍歷對象

for in 對數組遍歷的一個潛在bug是:如果有人在數組原型prototype添加了方法,或者引入了第三方js庫,庫中對數組原型進行了擴展,那么,for in 遍歷數組時將會把這些原型方法也遍歷出來,而for var 這種數組遍歷并不會遍歷出原型方法

舉例

var x=[1];

for(var s in x){
     alert(s);
};

====>輸出:0

var x=[1];

Array.prototype.toJson = 'xxx';
for(var s in x){
       alert(s);
};

===>輸出:0,toJson

若使用for var遍歷

var x=[1];

for(var i =0;i < x.length;i++){
       alert(i);
};

====>輸出:0

var x=[1];

Array.prototype.toJson = 'xxx';
for(var i =0;i < x.length;i++){
     alert(i);
};

====>輸出:0

由此可見for in遍歷數組會出現遍歷出原型方法的bug

如果堅持想用for in遍歷數組,可以考慮用ECMAScript5中的defineProperty方法來給數組原型上擴展,不過:1:defineProperty方法由于是ES5的,所以不支持IE9以下的瀏覽器 2:必須確保所有人都用這個方法來給數組進行擴展,要不遍歷就會出現問題

關于defineProperty:

這個新方法很厲害了,vue.js和avalon.js 都是通過它實現雙向綁定的,所以在這里有必要介紹一下

事例:

var a= {}

Object.defineProperty(a,"b",{
     value:123
})

console.log(a.b);//123

這個方法接收三個參數

第一個:目標對象

第二個:需要定義的屬性或者方法名

第三個:目標屬性所擁有的特性(descriptor)

這里主要介紹下第三個參數


value: 屬性的值

writable: true(屬性的值可以重寫),false(屬性值不能重寫,只能讀)

configurable: 總開關,如果為false, 就不能再設置他的(value,writable,configurable)

enumerable: 是否能在for in循環(huán)中遍歷出來或者在Object.keys中列舉出來。

get: 下面詳解

set: 下面詳解

知識點1:

如果未對writable,configurable,enumerable進行設置,會自動默認為false的初始值

知識點2:configurable

var a= {}

Object.defineProperty(a,"b",{
configurable:false
})

Object.defineProperty(a,"b",{
     configurable:true
})

//error: Uncaught TypeError: Cannot redefine property: b

就會報錯了。。注意上面講的默認值。。。如果第一次不設置它會幫你設置為false。。所以。。第二次。再設置他會報錯

知識點3:writable

知識點4:enumerable

這個是和我們上面介紹的for in 遍歷數組有關的解決方案

enumerable設置為fasle,將會禁止枚舉在defineProperty中定義的方法

set 和 get

在 descriptor 中不能 同時設置訪問器 (get 和 set) 和 wriable 或 value,否則會錯,就是說想用(get 和 set),就不能用(wriable 或 value中的任何一個)

var a= {}

Object.defineProperty(a,"b",{
set:function(newValue){
     console.log("你要賦值給我,我的新值是"+newValue)
},
get:function(){
     console.log("你取我的值")
     return 2 //注意這里,我硬編碼返回2
}
})

a.b = 1 //打印 你要賦值給我,我的新值是1
console.log(a.b)    //打印 你取我的值

//打印 2 注意這里,和我的硬編碼相同的

簡單來說,, 這個 “b” 賦值 或者 取值的時候會分別觸發(fā) set 和 get 對應的函數

除了通過defineProperty,還有一種方法可以避免遍歷出原型鏈方法:hasOwnProperty

可以用 hasOwnProperty 來確定這個屬性名是該對象的成員還是來自于原型鏈,如果對象擁有獨有的屬性,它將返回true,
hasOwnProperty 方法不會檢查原型鏈;

var obj = {
    name: 'wang',
    age: 21,
    getAge: function(){ },
    getName: function(){}
}
for(var i in obj){
    if( obj.hasOwnProperty(i) ){
        console.log(i)
    }
}

這樣,將會過濾掉原型鏈中的方法和屬性

雖然可以通過這兩種方法避免遍歷出原型鏈方法,但是還是強烈建議不要使用for in 去遍歷數組?。?/p>

寫完收工!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點點福利:阿里云產品券,享受所有官網優(yōu)惠,并抽取幸運大...
    HetfieldJoe閱讀 2,677評論 9 22
  • 博客內容:什么是面向對象為什么要面向對象面向對象編程的特性和原則理解對象屬性創(chuàng)建對象繼承 什么是面向對象 面向對象...
    _Dot912閱讀 1,536評論 3 12
  • 一簇迎春 迎來了一個春天 在時光中悄然盛開 不問花開幾許 只道淺笑安然 三月的風 吹醒了一片綠的繁盛 夢想著像他們...
    人類靈魂男工程師閱讀 427評論 0 2
  • 公司內部有這樣一句話:所有人都渴望有文檔,所有人都不喜歡寫文檔。深有體會深受其害。 文檔是沉淀,是歷史經驗的總結,...
    黑土錢閱讀 276評論 1 2
  • 利用SDWebImage下載圖片的原因 近期項目中有一個關于開屏廣告加的需求變更。需要客戶端將一段時間內的開屏廣告...
    Leafly閱讀 7,916評論 0 11

友情鏈接更多精彩內容