禁止使用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循环中遍历出来或者在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” 赋值 或者 取值的时候会分别触发 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 去遍历数组!!

写完收工!

你可能感兴趣的:(禁止使用for in 遍历对象)