实验代码
// 创建对象x,并分别赋值可遍历与不可遍历属性
let x = {}
x.name = 'tl'
Object.defineProperty(x, 'age', {
value: 17,
writable: true,
enumerable: false,
configurable: true
})
// 验证是否能遍历symbol属性的键名
Object.defineProperty(x, Symbol('symbolKey'), {
value: 'symbolVal',
writable: true,
enumerable: false, // 确认与enumerable属性无关
configurable: true
})
// 创建x的原型对象p,并分别赋值可遍历与不可遍历属性
let p = {}
p.sex = 'm'
Object.defineProperty(p, 'job', {
value: 'engineer',
writable: true,
enumerable: false,
configurable: true
})
x.__proto__ = p
in
'name' in x // true
'age' in x // true
'sex' in x // true
'job' in x // true
- 结论:对于
in
操作符,只要通过该对象可以访问该属性(在自身访问或通过原型链访问)
即返回true
,因为in
操作符没有进行枚举,因此不受enumerable
值的影响
for - in
for (let key in x) {
console.log(key)
}
// name
// sex
- 结论:拥有
in
操作符的特性,只要通过该对象可以访问该属性即可以遍历,因此可以得到原型链上的key
,同时由于for
是明显的枚举操作,因此会受到enumerable
值的影响,即不可遍历enumerable
为false
的值。即循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
Object.keys
Object.keys(x) // ["name"]
- 结论:只可访问对象自身的
key
,同时由于是遍历操作,因此会受到enumerable
值的影响,即不可遍历enumerable
为false
的值,返回一个key
组成的数组。即对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
Object.getOwnPropertyNames
Object.getOwnPropertyNames(x) // ["name", "age"]
- 结论:只可访问对象自身的key, 但是包括不可枚举的属性,即对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
Object.getOwnPropertySymbols
Object.getOwnPropertySymbols(x) // [Symbol(symbolKey)]
- 结论:返回一个数组,包含对象自身的所有 Symbol 属性的键名。(与enumerable无关)
Reflect.ownKeys
Reflect.ownKeys(x) // ["name", "age", Symbol(symbolKey)]
- 结论:返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。