如果想获得某个对象所有属性的列表,我们可以使用 for-in 循环。在第 2 章:基本
数据类型、数组、循环及条件表达式中,我们已经知道了如何使用该循环来遍历数组中的
所有元素。当时我们提到,for 更适合数组而 for-in 更适合对象。让我们以构造 URL
字符串为例:
var params = {
productid: 666,
section: 'products'
};
var url = 'http://example.org/page.php?',
i,
query = [];
for (i in params) {
query.push(i + '=' + params[i]);
}
url += query.join('&');
最后我们得到的变量 url 为:
"http://example.org/page.php?productid=666§ion=products"
在这里,有些细节需要留意。
并不是所有的属性都会在 for-in 循环中显示。例如(数组的)length 属性和
constructor 属性就不会被显示。那些会显示的属性被称为是可枚举的,我们
可以通过各个对象所提供的 propertyIsEnumerable()方法来判断对象的某
个属性是否可枚举。在 ES5 中,我们可以具体指定哪些属性可枚举,而在 ES3 中
没有这个功能。
原型链中的各个原型属性也会被显示出来,当然前提是它们是可枚举的。我们可
以通过对象的 hasOwnProperty()方法来判断一个属性是对象自身属性还是原
型属性。
对于所有的原型属性,propertyIsEnumerable()都会返回 false,包括那些
在 for-in 循环中可枚举的属性。
下面来看看这些方法具体是如何使用的。首先,我们来定义一个简化版的 Gadget():
function Gadget(name, color) {
= name;
this.color = color;
this.getName = function(){
return ;
};
}
Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;
然后新建一个对象:
var newtoy = new Gadget('webcam', 'black');
现在,如果对它执行 for-in 循环,就会列出该对象中的所有属性,包括原型中的
属性:
for (var prop in newtoy) {
console.log(prop + ' = ' + newtoy[prop]);
}
其结果甚至包括该对象的方法(因为方法本质上也可以被视为是函数类型的属性):
name = webcam
color = black
getName = function () {
return ;
}
price = 100
rating = 3
如果要对对象属性和原型属性做一个区分,就需要调用 hasOwnProperty()方法,
我们可以先来试一下:
> newtoy.hasOwnProperty('name');
true
> newtoy.hasOwnProperty('price');
false
下面我们再来循环一次,不过这次只显示对象的自身属性:
for (var prop in newtoy) {
if (newtoy.hasOwnProperty(prop)) {
console.log(prop + '=' + newtoy[prop]);
}
}
结果为:
name=webcam
color=black
getName=function () {
return ;
}
现在我们来试试 propertyIsEnumerable(),该方法会对所有的非内建对象属性返
回 true:
> newtoy.propertyIsEnumerable('name');
true
而对于内建属性和方法来说,它们大部分都是不可枚举的:
> newtoy.propertyIsEnumerable('constructor');
false
另外,任何来自原型链中的属性也是不可枚举的:
> newtoy.propertyIsEnumerable('price');
false
但是需要注意的是,如果 propertyIsEnumerable()的调用是来自原型链上的某个
对象,那么该对象中的属性是可枚举的。
> newtoy.constructor.prototype.propertyIsEnumerable('price');
true