禁止使用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 去遍历数组!!

写完收工!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 官方中文版原文链接 感谢社区中各位的大力支持,译者再次奉上一点点福利:阿里云产品券,享受所有官网优惠,并抽取幸运大...
    HetfieldJoe阅读 2,621评论 9 22
  • 博客内容:什么是面向对象为什么要面向对象面向对象编程的特性和原则理解对象属性创建对象继承 什么是面向对象 面向对象...
    _Dot912阅读 1,455评论 3 12
  • 一簇迎春 迎来了一个春天 在时光中悄然盛开 不问花开几许 只道浅笑安然 三月的风 吹醒了一片绿的繁盛 梦想着像他们...
    人类灵魂男工程师阅读 392评论 0 2
  • 公司内部有这样一句话:所有人都渴望有文档,所有人都不喜欢写文档。深有体会深受其害。 文档是沉淀,是历史经验的总结,...
    黑土钱阅读 260评论 1 2
  • 利用SDWebImage下载图片的原因 近期项目中有一个关于开屏广告加的需求变更。需要客户端将一段时间内的开屏广告...
    Leafly阅读 7,862评论 0 11