前文
在javascript中,对象的属性分为可枚举和不可枚举,他们是由property的enumerable值决定的。可枚举性决定了这个属性可否被for...in循环遍历到。
如何判断属性可否枚举
javascript中基本包装类型的原型属性是不可枚举的,如Object, Array, Number等,如果你写出这样的代码遍历其中的属性:
var str = new String()
for(var i in str) {
console.log("str." + i + " = " + str[i])
}
它的输出结果会是空。这是因为String中内置的属性是不可枚举的,所以不能被for…in访问到。
obj.propertyIsEnumerable
Object对象的obj.propertyIsEnumerable(prop)方法返回一个布尔值,可以判断此对象是否包含某个属性,并且这个属性是否可枚举,但是通过原型链继承的属性除外。
需要注意的是:如果判断的属性存在于Object对象的原型内,不管它是否可枚举都会返回false。
影响
如果一个属性的enumerable为false,会影响以下三个函数的结果:
-
for…in -
Object.keys() -
JSON.stringify
我们以下面的实例,逐一分析
function Person() {
this.name = 'isaac'
}
Person.prototype = {
constructor: Person,
job: 'programmer'
}
var isaac = new Person()
Object.defineProperty(
isaac,
'sex',
{
value: 'male',
enumerable: false // 不可枚举
}
)
如上,我们得到了一个Person构造函数,它自身有一个name属性,原型对象上有constructor和job属性,并且后期又自定义了一个不可枚举的sex属性,最后构造出了isaac实例对象。
我们分别对以上三个方法来做验证:
1. for in
for (var i in isaac) {
console.log(`isaac.${i} = ${isaac[i]}`)
}

如上,除了sex属性,其它都遍历出来了,包括其原型链上的job,constructor属性等等。
hasOwnProperty()
注意,如果你不想获取到原型链上的可枚举属性,可以使用hasOwnProperty()方法过滤掉。
for (var i in isaac) {
if(isaac.hasOwnProperty(i)) {
alert('this is my name: ' + isaac[i] + ' for sure !')
}
else {
alert('err')
}
}
// alert1: this is my name: isaac for sure !
// alert2~3: err!
如上,通过hasOwnProperty,我们过滤了那些从原型链上继承的可枚举属性,只保留了name这个自身可枚举属性。和in运算符不同,该方法会忽略掉那些从原型链上继承到的属性。
Object.getOwnPropertyNames
console.log(Object.getOwnPropertyNames(isaac))
// ["name", "sex"]
顺带一提,如上方法返回可枚举与不可枚举的自身属性。
2. Object.keys()
console.log(Object.keys(isaac))

如上,只返回了name,可见Object.keys()只返回给定对象的自身可枚举属性组成的数组。
3. JSON.stringify()
console.log(JSON.stringify(isaac))

此方法也只能读取对象本身的可枚举属性,并序列化为JSON对象。
以上三种方法和可枚举对象的关系一定要牢记哈!