判断属性存在或者遍历属性是日常开发中经常会用到。只是针对这些操作符、语句、方法,有些混淆。所以总结一下。
对象属性
对象属性目前只能是字符串值或者 symbol 值
A property key value is either an ECMAScript String value or a Symbol value
明确了这个规则后,开始下面的说明。
Property Attributes
翻译为属性的属性?这个概念我也有点说不清,看看下面的参考
Property Attributes 有 Value、Writable、Enumerable、Configurable。这个可以通过 Object.getOwnPropertyDescriptor 获取值。通过 Object.defineProperty 进行定义或者修改。
另外还有 Get、Set
本文的重点是讨论 Enumerable,这个值设置为 false 后,属性是不可遍历的。
但是不可遍历了,我还是需要获取这个属性该怎么办?
in 操作符
指定的属性在指定的对象或其原型链中,则in 运算符返回true
Reflect.has 和 in 的效果相同
这里的重点是 in 会检查原型链
console.log(length in []); // true
// 继承的 Symbol
console.log(Symbol.iterator in []); // true
// 继承的方法
console.log('toString' in []); // true
for...in 语句
for...in循环只遍历可枚举属性(包括它的原型链上的可枚举属性)
因此 for...in 的行为受到 Enumerable 的控制
for in 区别 // 遍历除了 symbol 以外的可枚举属性
let obj = {
[Symbol('my_key')]: 1,
enum: 2,
nonEnum: 3
};
Object.defineProperty(obj,
'nonEnum', { enumerable: false });
console.log(Object.keys(obj))
let obj2 = Object.create(obj)
obj2.myVal = 5
console.log(obj2); // { myVal: 5 }
for (var prop in obj2) {
console.log('obj2 prop: ', prop); // myVal, enum
}
Object 对象的一些方法
Object.keys
会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for...in 循环遍历该对象时返回的顺序一致 。
// 省略上面的代码
Object.keys(obj) // ['enum']
Object.keys(obj2) // ['myVal']
Object.getOwnPropertyNames
返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
// 省略上面的代码
Object.getOwnPropertyNames(obj) // ['enum', 'nonEnum']
Object.prototype.hasOwnProperty 用来判断对象自身属性。
一个常用的判断:遍历一个对象的所有自身属性
var buz = {
fog: 'stack'
};
for (var name in buz) {
if (buz.hasOwnProperty(name)) {
console.log('this is fog (' +
name + ') for sure. Value: ' + buz[name]);
}
else {
console.log(name); // toString or something else
}
}
Object.getOwnPropertySymbols
返回一个给定对象自身的所有 Symbol 属性的数组
// 省略上面的代码
Object.getOwnPropertySymbols(obj) // [ Symbol(my_key) ]
Reflect.ownKeys
上面的方法操作符,饶了一圈。和 Enumerable Symbol 的有无打交道。
有没有方法能够拿到所有的属性 (我全都要.webp)
答案就是: Reflect.ownKeys
// 省略上面的代码
Reflect.ownKeys(obj) // [ Symbol(my_key), 'enum', 'nonEnum' ]
总结
对象属性目前只能是字符串值或者 symbol 值。所以下面的情况会出现 toPrimitive 或者 toString 的转换
let obj3 = {
[obj]: 33
}
// { '[object Object]': 33 }
当然需要使用对象作为 key, 需要用到 Map 了,这些是后话。
一般情况下都是用 Object.keys 来遍历自身可枚举属性。Object.keys 是 ES5 的标准。
以前 ES3 的时候是需要 in 操作符 和 hasOwnProperty 配合使用
全都要的情况: Reflect.ownKeys
要考虑 Enumerable 为 false 时, 用 Object.getOwnPropertyNames
要考虑 Symbol 时, 用 Object.getOwnPropertySymbols
参考链接
MDN
in - JavaScript | MDN Keys in Javascript objects can only be strings? - Stack Overflow