内容整理自:Enumerability and ownership of properties - JavaScript | MDN (mozilla.org)
枚举性:
- 字面量创建对象属性时,默认是可枚举的。
- 使用 Object.defineProperty 创建属性时,默认是不可枚举的。
js 中有四种方式可以判断某个属性是否存在该对象身上。下面表格对其进行了归纳和总结。
- ✅ 表示能判断这种属性是否存在
- ❌ 表示无法判断这种属性是否存在。即:始终返回
false
自身、可枚举属性 | 自身、不可枚举属性 | 自身、symbol 属性 | 继承、可枚举属性 | 继承、不可枚举属性 | 继承、symbol 属性 | |
---|---|---|---|---|---|---|
in | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Object.hasOwn() | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
hasOwnProperty() | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
propertyIsEnumerable() | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
下面表格总结了 js 中可以遍历对象属性的方式,以及这种方式能否访问到某类属性。
- ✅ (strings) 表示只有当该属性是 string 类型时才能访问到。
- ✅ (symbols) 表示只有当该属性是 symbol 类型时才能访问到。
- ❌表示访问不到。
自身、可枚举的属性 | 自身、不可枚举属性 | 自身、symbol 属性 | 继承、可枚举属性 | 继承、不可枚举属性 | 继承、symbol 属性 | |
---|---|---|---|---|---|---|
Object.keys Object.values Object.entries | ✅ (strings) | ❌ | ❌ | ❌ | ❌ | ❌ |
Object.getOwnPropertyNames | ✅ (strings) | ✅ (strings) | ❌ | ❌ | ❌ | ❌ |
Object.getOwnPropertySymbols | ❌ | ❌ | ✅ (symbols) | ❌ | ❌ | ❌ |
Object.getOwnPropertyDescriptors | ✅ (strings) | ✅ | ✅ (symbols) | ❌ | ❌ | ❌ |
Reflect.ownKeys | ✅ (strings) | ✅ | ✅ (symbols) | ❌ | ❌ | ❌ |
for…in | ✅ (strings) | ❌ | ❌ | ✅ (strings) | ❌ | ❌ |
此外,还有一些其他方法,也涉及到属性
自身、可枚举的属性 | 自身、不可枚举属性 | 自身、symbol 属性 | 继承、可枚举属性 | 继承、不可枚举属性 | 继承、symbol 属性 | |
---|---|---|---|---|---|---|
Object.assign 其中的 sourceN 参数 | ✅ (strings) | ❌ | ✅ (symbols) | ❌ | ❌ | ❌ |
展开运算符 … | ✅ (strings) | ❌ | ✅ (symbols) | ❌ | ❌ | ❌ |
下面是测试代码:
const inheritSymbol = Symbol('继承 symbol 属性')
const ownSymbol = Symbol('自身 symbol 属性')
const parent = {
'继承可枚举属性': 0,
[inheritSymbol]: 0
}
Object.defineProperty(parent, '继承不可枚举属性', {})
const obj = Object.create(parent)
obj['自身可枚举属性'] = 0
Object.defineProperty(obj, '自身不可枚举属性', {})
obj[ownSymbol] = 0
console.log('\nin')
console.log('自身可枚举属性' in obj, ' \t自身可枚举属性')
console.log('自身不可枚举属性' in obj, ' \t自身不可枚举属性')
console.log(ownSymbol in obj, ' \townSymbol')
console.log('继承可枚举属性' in obj, ' \t继承可枚举属性')
console.log('继承不可枚举属性' in obj, ' \t继承不可枚举属性')
console.log(inheritSymbol in obj, ' \tinheritSymbol')
console.log('\nObject.hasOwn')
console.log(Object.hasOwn(obj, '自身可枚举属性'), ' \t自身可枚举属性')
console.log(Object.hasOwn(obj, '自身不可枚举属性'), ' \t自身不可枚举属性')
console.log(Object.hasOwn(obj, ownSymbol), ' \townSymbol')
console.log(Object.hasOwn(obj, '继承可枚举属性'), ' \t继承可枚举属性')
console.log(Object.hasOwn(obj, '继承不可枚举属性'), ' \t继承不可枚举属性')
console.log(Object.hasOwn(obj, inheritSymbol), ' \tinheritSymbol')
console.log('\nhasOwnProperty')
console.log(obj.hasOwnProperty('自身可枚举属性'), ' \t自身可枚举属性')
console.log(obj.hasOwnProperty('自身不可枚举属性'), ' \t自身不可枚举属性')
console.log(obj.hasOwnProperty(ownSymbol), ' \townSymbol')
console.log(obj.hasOwnProperty('继承可枚举属性'), ' \t继承可枚举属性')
console.log(obj.hasOwnProperty('继承不可枚举属性'), ' \t继承不可枚举属性')
console.log(obj.hasOwnProperty(inheritSymbol), ' \tinheritSymbol')
console.log('\npropertyIsEnumerable')
console.log(obj.propertyIsEnumerable('自身可枚举属性'), ' \t自身可枚举属性')
console.log(obj.propertyIsEnumerable('自身不可枚举属性'), ' \t自身不可枚举属性')
console.log(obj.propertyIsEnumerable(ownSymbol), ' \townSymbol')
console.log(obj.propertyIsEnumerable('继承可枚举属性'), ' \t继承可枚举属性')
console.log(obj.propertyIsEnumerable('继承不可枚举属性'), ' \t继承不可枚举属性')
console.log(obj.propertyIsEnumerable(inheritSymbol), ' \tinheritSymbol')
console.log('\nObject.keys')
console.log(Object.keys(obj))
console.log('\nObject.getOwnPropertyNames')
console.log(Object.getOwnPropertyNames(obj))
console.log('\nObject.getOwnPropertySymbols')
console.log(Object.getOwnPropertySymbols(obj))
console.log('\nObject.getOwnPropertyDescriptors')
console.log(Object.getOwnPropertyDescriptors(obj))
console.log('\nReflect.ownKeys')
console.log(Reflect.ownKeys(obj))
console.log('\nfor...in')
for (const key in obj) { console.log(key) }
console.log('\nObject.assign')
console.log('自身可枚举属性' in Object.assign({}, obj), ' \t自身可枚举属性')
console.log('自身不可枚举属性' in Object.assign({}, obj), ' \t自身不可枚举属性')
console.log(ownSymbol in Object.assign({}, obj), ' \townSymbol')
console.log('继承可枚举属性' in Object.assign({}, obj), ' \t继承可枚举属性')
console.log('继承不可枚举属性' in Object.assign({}, obj), ' \t继承不可枚举属性')
console.log(inheritSymbol in Object.assign({}, obj), ' \tinheritSymbol')
console.log('\nObject spread ...')
console.log('自身可枚举属性' in {...obj}, ' \t自身可枚举属性')
console.log('自身不可枚举属性' in {...obj}, ' \t自身不可枚举属性')
console.log(ownSymbol in {...obj}, ' \townSymbol')
console.log('继承可枚举属性' in {...obj}, ' \t继承可枚举属性')
console.log('继承不可枚举属性' in {...obj}, ' \t继承不可枚举属性')
console.log(inheritSymbol in {...obj}, ' \tinheritSymbol')