如同 in 运算符一样,使用 for in 循环遍历对象属性时,也将往上遍历整个原型链。

// Poisoning Object.prototype
Object.prototype.bar = 1; var foo = { moo: 2 };
for(var i in foo) {
console.log(i); // prints both bar and moo
}

这里我们要注意两点,一是 for in 循环会忽略 enumerable 设置为 false 的属性。例如一个数组的 length 属性。第二是,由于 for in 会遍历整个原型链,所以当原型链过长时,会对性能造成影响。

enumerable 是个很陌生的词汇,实际上,你很难在 JavaScript 中发现它的影子,而它实际上也是作者从 ruby中借鉴而来的。创建 enumerable 的目的不是为了独立使用,而是采用“混用”的方式,而 Prototype 中很多方法都混用了 enumerable,所以它可以说是 prototype 的奠基石。这里不做详细介绍,详细内容可以参考 -Enumerable

由于我们没法改变 for in 循环本身的行为,所以我们只能采取其他方法来过滤掉那些不希望出现在循环内的属性,通过《细说 JavaScript 对象篇(三) : hasOwnProperty》 我们知道 hasOwnProperty 方法是可以做到这一点的。

使用 hasOwnProperty 过滤

仍然使用上个例子:

// Poisoning Object.prototype
Object.prototype.bar = 1; var foo = {
moo : 2
};
for (var i in foo) {
if (foo.hasOwnProperty(i)) {
console.log(i);
}
}

这是唯一正确的写法,由于我们实用了 hasOwnProperty 方法,所以这次只输出 moo。如果不适用 hasOwnProperty 方法,那么当 Object.prototype 扩展时,就会出现错误。

现在很多框架都会选择从 Object.prototype 扩展方法,所以我们使用这些框架时,如果使用没有用 hasOwnProperty 过滤的 for in 循环时就会遇到问题。

总结

建议养成 hasOwnProperty 过滤属性的好习惯,不要对运行环境做任何假设,也无论原生的原型对象是否被扩展。

参考

http://segmentfault.com/blog/stephenlee/1190000000480560

http://bonsaiden.github.io/JavaScript-Garden/#object.forinloop

延伸阅读:

细说JavaScript对象(1):对象的使用和属性

细说JavaScript对象(2):原型对象

细说JavaScript对象(3):hasOwnProperty

细说JavaScript对象(4): for in 循环

细说JavaScript对象(4): for in 循环的更多相关文章

  1. 细说JavaScript对象(2):原型对象

    JavaScript 并没有类继承模型,而是使用原型对象 prototype 进行原型式继承. 尽管人们经常将此看做是 JavaScript 的一个缺点,然而事实上,原型式继承比传统的类继承模型要更加 ...

  2. 细说JavaScript对象(3):hasOwnProperty

    判断一个属性是定义在对象本身而不是继承自原型链,我们需要使用从 Object.prototype 继承而来的 hasOwnProperty 方法. hasOwnProperty 方法是 JavaScr ...

  3. 细说JavaScript对象(1):对象的使用和属性

    JavaScript 中的一切都可以视为对象,除了两个特例:null 和 undefined. false.toString(); // 'false' [1, 2, 3].toString(); / ...

  4. 10 JavaScript对象&类&for循环

    JavaScript对象 JavaScript中所有事物都是对象:字符串.数值.数组.函数.数学和正则表达式 JavaScript有些类型可以是字面量而非对象:如字符串.数值.布尔值 JavaScri ...

  5. 细说JavaScript单线程的一些事

    标签: JavaScript 单线程 首发地址:码农网<细说JavaScript单线程的一些事> 最近被同学问道 JavaScript 单线程的一些事,我竟回答不上.好吧,感觉自己的 Ja ...

  6. 简述JavaScript对象、数组对象与类数组对象

    问题引出 在上图给出的文档中,用JavaScript获取那个a标签,要用什么办法呢?相信第一反应一定是使用document.getElementsByTagName('a')[0]来获取.同样的,在使 ...

  7. 深入理解javascript对象系列第二篇——属性操作

    × 目录 [1]查询 [2]设置 [3]删除[4]继承 前面的话 对于对象来说,属性操作是绕不开的话题.类似于“增删改查”的基本操作,属性操作分为属性查询.属性设置.属性删除,还包括属性继承.本文是对 ...

  8. Javascript并发模型和事件循环

    Javascript并发模型和事件循环 JavaScript的"并发模型"是基于事件循环的,这个并发模型有别于Java的多线程, javascript的并发是单线程的. Javas ...

  9. web前端学习(二) javascript对象和原型继承

    目录 1. JavaScrpt对象 2. 原型对象和继承 3. 对象的克隆 (1)javascript对象 在JS中,对象是属性的容器.对于单个对象来说,都由属性名和属性值构成:其中属性名需要是标识符 ...

随机推荐

  1. oom 和 jvm crash的问题

    很多次生产环境jvm进程无故消失的时候都留下了hs_err[pid].log文件  然后通过mat分析大多数情况是oom导致的  所以以前一直认为OOM一定会导致jvm crash  也就是说java ...

  2. Eureka 使用Spring cloud config 管理中心启动

    Config 工程创建之后,Eureka就可以使用Git上的配置启动服务了. Git 服务器的搭建这里就不细说了(自行解决),下面是我上传再git的配置文件: 创建EurekaServer项目(eur ...

  3. 九 DIP 依赖倒置原则

    首先看定义: 1.高层模块不依赖于低层模块,两者都应该依赖于抽象层 2.抽象不能依赖于细节,细节必须依赖于抽象 首先,模块是个抽象的概念,可以大到一个系统中的子系统作为一个模块,也可以是某个子系统中的 ...

  4. sass mixin 持续更新

    控制多行显示省略号... //文字溢出省略号@mixin coveText($num:1){ @if $num == 1{ white-space: normal; overflow: hidden; ...

  5. 如何禁用Eclipse的Validating

    使用Eclipse开发项目,在加载项目.刷新项目.修改了某个代码的时候,经常出现Eclipse正在Validating的提示.项目比较大文件(js)较多的情况下,甚至出现Validating几分钟的盛 ...

  6. 《c程序设计语言》读书笔记-5.5-指针实现strncpy,strncat,strncmp

    #include <stdio.h> #include <math.h> #include <stdlib.h> #include <string.h> ...

  7. ES6特性以及代码demo

    块级作用域let if(true){ let fruit = ‘apple’; } consoloe.log(fruit);//会报错,因为let只在if{ }的作用域有效,也就是块级作用域 恒量co ...

  8. C#操作XML序列化与反序列化

    public class XmlSerializerHelper { /// <summary> /// 从XML文件中反序列化读取对象 /// </summary> /// ...

  9. 我读过的最好的epoll讲解--转自”知乎“ 【转】

    转自:http://blog.csdn.net/xu3737284/article/details/12715963 首先我们来定义流的概念,一个流可以是文件,socket,pipe等等可以进行I/O ...

  10. Windows基础-使用XAudio2播放音频(本质是WASAPI)

    对于常见的音频播放,使用XAudio2足够了. 时间是把杀猪刀,滑稽的是我成了猪 早在Windows Vista中,M$推出了新的音频架构UAA,其中的CoreAudio接替了DSound.WaveX ...