JS中的可枚举属性与不可枚举属性
什么是枚举?枚举是指对象中的属性是否可以遍历出来,再简单点说就是属性是否可以以列举出来。
⼀、怎么判断属性是否可枚举
在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的。可枚举性决定了这个属性能否被for…in查遍历到。      js中的基本包装类型的原型属性是不可枚举的,⽐如Object,Array,Number等
这是⼀个例⼦:
var num = new Number();
for(var pro in num) {
console.log("num." + pro + " = " + num[pro]);
}
//此处没有输出
它的输出结果是空的,因为Number中的内置属性是不可枚举的,所以不能被 for ... in 访问到
每个对象都有propertyIsEnumerable()⽅法,这个⽅法可以判断出指定的属性是否可枚举。
⽤法:
obj.propertyIsEnumerable("属性名");
function Person(){
this.name = "我是实例属性"
this.age = 19;
}
var p = new Person();
console.log(p.propertyIsEnumerable("name")); //true
Person.prototype.prop = "我是原型属性" //添加⼀个原型属性
console.log(p.propertyIsEnumerable("prop")); //false prop是继承⾃原型上的属性,所以返回的是false
for(var k in p){
console.log(k+","+p[k]);//name,我是实例属性  age,19  prop,我是原型属性
}
从中也可以发现,如果是对象的原型链中的属性,不管是否枚举都会返回false。
但是 for ...in 仍然可以读出原型链中的可枚举属性
⼆、枚举属性的作⽤
枚举属性主要会影响⼏个⽅法
ES5中:
Object.keys()            //返回对象⾃⾝的所有可枚举的属性的键名
JSON.stringify          //JSON.stringify() ⽅法⽤于将 JavaScript 值转换为 JSON 字符串。
ES6中:
Object.assign()          //会忽略enumerable为false的属性,只拷贝对象⾃⾝的可枚举的属性。
可以看出来这些都是可以遍历对象的⽅法,⽽这四个操作中只有in中会返回继承的属性
先看⼀个例⼦,创建⼀个"xsy"对象:
function Person(){
this.name = "XSY"
};
Person.prototype = {
constructor: Person,
job:"student",
};
var xsy = new Person();
Object.defineProperty(xsy, "sex",{
value:"female",
enumerable:false
});
这⾥⽤defineProperty⽅法定义了⼀个叫"sex"的不可枚举属性
然后可以开始验证了:
a.  in
for(var pro in xsy){
console.log("xsy." + pro+ " = " + xsy[pro]);
}
输出的结果如下,可以发现对象中声明的属性,原型链上绑定的属性成功输出了,⽽不可枚举属性“sex”没有输出。
b.  Object.keys()
js原型和原型链的理解console.log(Object.keys(xsy));
从输出结果可以发现,这⾥只输出了对象声明的可枚举属性,但是没有输出原型链中的可枚举属性
c. JSON.stringify
console.log(JSON.stringify(xsy));
这⾥的输出也和上⾯⼀样,结果中只有对象中的可枚举属性没有原型链中的。
从上⾯这些操作中⼤概可以明⽩了,可枚举性决定了这个属性能否被for…in查遍历到。所以可枚举与否都是开发者⾃⼰定义的,
可以通过Object.defineProperty()⽅法。
三、设置可枚举属性
其实在上⾯的例⼦中已经使⽤到了设置enumerable的⽅法:Object.defineProperty()
var person = {
name:'xiao',
age: '18',
sex: 'boy'
}
Object.defineProperty(person,'age',{
enumerable:true,//可以被枚举
});
Object.defineProperty(person,'sex',{
enumerable:false,//不可以被枚举
})
for(var k in person){
console.log(person[k])//a,可以被枚举
}
//18
//xiao
从上⾯可以看出:
1.Object.defineProperty(obj, prop, descriptor)⽅法有三那个参数
第⼀个:⽬标对象
第⼆个:⽬标属性,字符串
第三个:对⽬标属性的⾏为,放在对象⾥
3.开发者⾃⼰定义的对象person中的所有属性默认都是可枚举的;
四、如何判断是否可枚举-- propertyIsEnumerable
有时候不知道对象的可枚举性,该怎么判断呢。propertylsEnumerable()⽅法可以解决这个问题
person.propertyIsEnumerable('sex');//false
person.propertyIsEnumerable('age');//true
propertyIsEnumerable() 语法:
1. 语法:obj.propertyIsEnumerable(prop)
2. 描述:每个对象都有⼀个propertyIsEnumerable⽅法。此⽅法可以确定对象中指定的属性是否可枚举,返回⼀个布尔值。但该⽅法对通过原型链继承的属性⽆效(原型
链继承的属性是否可枚举不能⽤该⽅法来判断)
3. 案例:
4. 1)⽤户⾃定义对象和引擎内置对象的区别
Math.propertyIsEnumerable('random');  // 返回 false
Object.propertyIsEnumerable('constructor');    // 返回 false
var num = new Number();
for(var pro in num) {
console.log("num." + pro + " = " + num[pro]);
}//输出空
1. 这说明了开发者⾃定义的属性在⼀般情况下时可以枚举的,但是内置的对象Math和基本包装类型⾥的属性是不可枚举的,如Object, Array, Number等;其
实,propertyIsEnumerable⽅法只对对象⾃⾝的属性(对象⾃⾝添加的、构造函数实例化的)有效,对原型上的、继承来的属性都⽆效。
五、总结
1.  in循环是遍历对象的每⼀个可枚举属性,包括原型链上⾯的可枚举属性;
2. ⽽Object.keys()只是遍历⾃⾝的可枚举属性,不可以遍历原型链上的可枚举属性. 这是in和Object.keys()的主要区别;
3. OwnPropertyNames()则是遍历⾃⾝所有属性(不论是否是可枚举的),不包括原型链上⾯的。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。