属性的可枚举性
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
// {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
// }
描述对象的enumerable属性,称为”可枚举性“,如果该属性为false,就表示某些操作会忽略当前属性。可以用
Object.defineProperty(obj,prop,{
enumerable: true,
});
改变描述对象的enumerable
ES5有三个操作会忽略enumerable为false的属性。
• for…in循环:只遍历对象自身的和继承的可枚举的属性
• Object.keys():返回对象自身的所有可枚举的属性的键名
• JSON.stringify():只串行化对象自身的可枚举的属性
ES6新增了一个操作Object.assign(),会忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。
这四个操作之中,只有for…in会返回继承的属性。实际上,引入enumerable的最初目的,就是让某些属性可以规避掉for…in操作。比如,对象原型的toString方法,以及数组的length属性,就通过这种手段,不会被for…in遍历到。
Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable
// false
Object.getOwnPropertyDescriptor([], 'length').enumerable
// false
上面代码中,toString和length属性的enumerable都是false,因此for…in不会遍历到这两个继承自原型的属性。
另外,ES6规定,所有Class的原型的方法都是不可枚举的。
Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable
// false
总的来说,操作中引入继承的属性会让问题复杂化,大多数时候,我们只关心对象自身的属性。所以,尽量不要用for…in循环,而用Object.keys()代替。
属性的遍历
ES6一共有5种方法可以遍历对象的属性。
(1)for…in
for…in循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)。
可以顺便的到属性值
for(var key in obj) {
console.log(key);
console.log(obj[key])
}
(2)Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)。
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有Symbol属性。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有属性,不管是属性名是Symbol或字符串,也不管是否可枚举。
以上的5种方法遍历对象的属性,都遵守同样的属性遍历的次序规则。
• 首先遍历所有属性名为数值的属性,按照数字排序。
• 其次遍历所有属性名为字符串的属性,按照生成时间排序。
• 最后遍历所有属性名为Symbol值的属性,按照生成时间排序。
Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })
// ['2', '10', 'b', 'a', Symbol()]
上面代码中,Reflect.ownKeys方法返回一个数组,包含了参数对象的所有属性。这个数组的属性次序是这样的,首先是数值属性2和10,其次是字符串属性b和a,最后是Symbol属性。
其它
- jquery 的 each 方法
循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)。
$.each( obj, function( key, value ) {
alert( key + ": " + value );
});
- Object.values()
Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
var obj = { foo: "bar", baz: 42 };
Object.values(obj)
// ["bar", 42]
返回数组的成员顺序,与上面的《属性的遍历》部分介绍的排列规则一致。
var obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"]
Object.values只返回对象自身的可遍历属性。
var obj = Object.create({}, {p: {value: 42}});
Object.values(obj) // []
上面代码中,Object.create方法的第二个参数添加的对象属性(属性p),如果不显式声明,默认是不可遍历的。Object.values不会返回这个属性。
如果Object.values方法的参数是一个字符串,会返回各个字符组成的一个数组。
Object.values('foo')
// ['f', 'o', 'o']
如果参数不是对象,Object.values会先将其转为对象。由于数值和布尔值的包装对象,都不会为实例添加非继承的属性。所以Object.values会返回空数组。
Object.values(42) // []
Object.values(true) // []
- Object.entries
Object.entries方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
var obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]