先把总结写在这里:
- JavaScript对象的属性可分为可枚举和不可枚举,它是由属性的
enumeration
值决定的,true
为可枚举,false
为不可枚举 - 原生构造函数(Boolean, Number, String 等)的内置属性(例如 toSring、 constructor等) 和 引擎内置对象的属性(Math 的 random 等) 一般是不可枚举的,而自己定义的属性(不管是原型上的还是自身的)一般是可枚举的。
- 属性的枚举性会影响以下四个方法的结果
1)for...in
2 )Object.keys()
3)JSON.stringify()
4)Object.assign()
小结:
- 这四个方法中,只有
for/in
是对所有可枚举属性(对象本身的可枚举属性,以及从其构造函数原型中继承的可枚举属性),而其他三种是对自身可枚举属性才有效。 - 而四个方法中又只有
Object.assign()
对 Symbol 属性有效,其他三种对 Symbol 都会过滤掉。
这里做一个其他的小总结: - 上面四个方法中,其中
Object.assign()
无法正确拷贝get属性和set属性,而JSON.stringify()
对对象的方法、undefined值、get 属性、set属性无效 。 - 如果该参数不是对象,则会先转成对象,然后返回。
由于undefined和null无法转成对象,所以如果它们作为(第一个)参数,就会报错。有这两种特性的方法是:
Object.assign() 、 Object.setPrototypeOf()、Object.getPrototypeOf()
上面说了JavaScript对象的属性是否可枚举是 enumeration 的值决定的,那么enumeration是什么时候怎么去设置的呢?
enumeration 是 Object.defineProperty() 方法的一个参数,下面来看看怎么去设置 一个属性是否可枚举。
var person = {
name:'zhou',
age: '12',
sex: 'girl'
}
Object.defineProperty(person,'age',{
enumerable:true,//可以被枚举
});
Object.defineProperty(person,'sex',{
enumerable:false,//可以被枚举
})
for(var k in person){
console.log(person[k])//a,可以被枚举
}
//12
//zhou
如何设置是否可枚举-- enumerable
由上面的点可以看出:
1.Object.defineProperty(obj, prop, descriptor)方法有三个参数,每个参数各代表着
第一个:目标属性所在的对象,
第二个:目标属性,放在字符串里,
第三个:目标属性的行为,放在对象里;
2.enumerable为true表示可枚举,enumerable为false表示不可枚举;
3.开发者自定义的对象person的所有属性都是可枚举的;
如何判断是否可枚举-- obj.propertyIsEnumerable()
在不知情的情况下,如何判断一个属性是否可枚举呢?obj.propertylsEnumerable()方法可以解决这个问题。
- 语法:obj.propertyIsEnumerable(prop)
- 定义:每个对象都有一个
propertyIsEnumerable
方法,表示指定的自身属性是否可枚举 (继承属性无效) ,返回一个布尔值(当对象没有该指定属性时也返回 false)。 - 用法:
1)就上面的例子的使用
person.propertyIsEnumerable('name');//true
person.propertyIsEnumerable('age');//true
person.propertyIsEnumerable('sex');//false
2)引擎内置对象的属性不可枚举
var o = {};
var a = [];
o.prop = 'is enumerable';
a[0] = 'is enumerable';
o.propertyIsEnumerable('prop') // true
a.propertyIsEnumerable(0); // true
Math.propertyIsEnumerable('random') // false
Object.propertyIsEnumerable('constructor') // false
从 用法1 和 用法2 可以看出用户自定义属性是可枚举的(一般情况下自定义属性都是可枚举的,除非像 person.sex 经过属性描述符的修改),而浏览器内置对象如 Math 的属性是不可枚举的。
3)原生构造函数的内置属性不可枚举,如Boolean, Number, String, Array, Date, Function, RegExp, Error, Object
var num = new Number();
for(var prop in num) {
console.log(prop);
}
输出为空。for in 访问的是所有可枚举属性,这里输出为空,说明Number中内置的属性是不可枚举的,例如 toString() 方法。
4)自定义属性一般为可枚举属性( 不管是自身属性还是原始上的继承属性 )
说明:
- 开发者自定义的属性在一般情况下是可枚举的
-
for /in
对所可以访问到所有可枚举属性 -
obj.propertyIsEnumerable(prop)
只能访问到 对象自身可枚举属性(对象自身添加的、构造函数实例化的) 有效,对原始上的继承属性无效。 -
obj.hasOwnProperty(prop)
返回一个布尔值,指示对象自身属性中是否具有指定的属性 -
Object.getOwnPropertyNames(obj)
返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。 -
Object.keys()
方法会返回一个由一个给定对象的自身可枚举属性组成的数组。
//构造函数
function People() {
this.hobby = 'eat';
}
People.prototype.showHooby = function() {};
//继承
function Coder() {
this.love = function method() { return 'coder‘s love is codeing'; };
}
Coder.prototype = new People;
Coder.prototype.constructor = Coder;
//实例
var c = new Coder();
c.age = '24';
//打印出实例
console.dir(c)
我们来看看打印出来的实例对象,看看哪些属性是自身的,哪些属性是在原型上的
image.png
用 for/in
来访问 o
对象,看看哪些属性是可枚举的:
for(var prop in c){
console.log(prop)
}
// love
// age
// hobby
// constructor
// showHooby
自定义属性都可枚举,不管是自身属性还是原始上的继承属性
怎么过滤出自身可枚举属性呢?就可以用 obj.propertyIsEnumerable()
, Object.getOwnPropertyNames()
, obj.hasOwnProperty
, Object.keys()
方法啦
// obj.propertyIsEnumerable() --- 先找出*所有可枚举属性*,再找出自身的可枚举属性
for(var prop in c){
if(c.propertyIsEnumerable(prop)) console.log(prop)
}
// love
// age
// 或者 obj.hasOwnProperty() --- 先找出*所有可枚举属性*,再找出自身属性
for(var prop in c){
if(c.hasOwnProperty(prop)) console.log(prop)
}
// love
// age
// 或者 Object.getOwnPropertyNames() --- 先找出*所有自身属性*的属性名,再找出可枚举的
var cName = Object.getOwnPropertyNames(c);
for(var prop in cName){
console.log(cName[prop])
}
// love
// age
// 或者 Object.keys() --- 直接找出自身可枚举属性
Object.keys(c)
//["love", "age"]
参考链接:
MDN:Object
MDN: 属性的可枚举性和所有权
自己总结了大半天,然后看到阮大神比较全的一篇:
阮一峰:属性的可枚举与遍历
上面说到关于对象属性“枚举性”的多种方法,这里放放上一张这些属性微妙差别的对比图:
属性的可枚举性和所有权
网友评论