如果想获得某个对象所有属性的列表,我们可以使用 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&section=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