javascript的for-in陷阱以及对象原型的枚举属性

for...in循环中的循环计数器是字符串,而不是数字。它包含当前属性的名称或当前数组元素的索引。

当遍历一个数组的时候,变量 i 也就是循环计数器 为当前数组元素的索引:

var a = [1,2,3];  
for(var i in a){  
   console.log("a["+i+"]="+a[i]);
}

产生的结果如下:
a[0]=1
a[1]=2
a[2]=3

当遍历一个对象的时候,变量 i 也就是循环计数器 为对象的属性名:

var o = {p1:1,p2:2};  
for(var i in o){  
    console.log(i+"="+o[i]);
}

产生的结果如下:
p1=1
p2=2

需要留意的是:

  • 并不是所有的属性都会在for-in循环中显示。例如(数组的)length属性和constructor属性就不会被显示。那些已经被显示的属性被称为是可枚举的,可以通过各个对象所提供的propertyIsEnumerable()方法来判断其中有哪些可枚举的属性。
  • 原型链中的各个原型属性也会被显示出来,当然前提是他们是可枚举的。可以通过对象的hasOwnProperty()方法来判断一个属性是对象自身属性还是原型属性。
  • 对于内建属性和方法、以及所有的原型属性,propertyIsEnumerable()都会返回false,包括那些在for-in循环中可枚举的原型属性。
//定义一个Gadget对象构造器函数
function Gadget(name,color){  
    this.name=name;
    this.color=color;
    this.someMethod=function(){return 1;}
}
//通过构造器函数添加原型属性price和rating
Gadget.prototype.price=100;  
Gadget.prototype.rating=3;  
//新建一个Gadget对象
var newtoy=new Gadget('webcam','black');  
//使用for-in循环该对象的所有属性
for(var i in newtoy){  
    console.log(i+" = " + newtoy[i]);
}

log结果:
name = webcam
color = black
//对象方法也被显示出来(因为方法本质上也可以被视为是函数类型的属性)
someMethod = function (){return 1;}
price = 100
rating = 3

newtoy.hasOwnProperty('name');//自身属性name  

结果:
true

newtoy.hasOwnProperty('price');//原型属性price  

结果:
false

//只遍历newtoy对象的自身属性
for(var i in newtoy){  
    if (newtoy.hasOwnProperty(i)) {
        console.log(i+" = " + newtoy[i]);
    };  
}

结果:
name = webcam
color = black
someMethod = function (){return 1;}

newtoy.propertyIsEnumerable('name');//name是非内建对象属性  

结果:
true

newtoy.propertyIsEnumerable('constructor');//内建对象constructor  

结果:
false

newtoy.propertyIsEnumerable('price');//任何来自原型链中的属性也是不可枚举的  

结果:
false

newtoy.constructor.prototype.propertyIsEnumerable('price');//如果propertyIsEnumerable()的调用是来自原型链上的某个对象,那么该对象中的属性是可枚举的。  

结果:
true

//只遍历newtoy对象的可枚举属性
for(var i in newtoy){  
    if (newtoy.propertyIsEnumerable(i)) {
        console.log(i+" = " + newtoy[i]);
    };
}

结果:
name = webcam
color = black
someMethod = function (){return 1;}

到这里发现通过hasOwnProperty()和propertyIsEnumerable()判断对象属性进行排除后得到的显示结果是一样的,那么hasOwnProperty()和propertyIsEnumerable()这两个函数的区别是什么呢?

看这篇进行了解:hasOwnProperty()和propertyIsEnumerable()的区别

Wilson

张弛有度、简约不简单