对象的两类属性
对象的属性有两种类型:字符串和 Symbol。
var sybProp = Symbol()
var strProp = 'str'
var objProp = {}
var obj = {
[sybProp]: 'This is a String property',
[strProp]: 'This is a Symbol property',
[objProp]: 'This is also a String property'
}
obj
// {
// str: "This is a String property",
// [object Object]: "This is also a String property",
// Symbol(): "This is a Symbol property"
// }
因为对象只支持字符串和 Symbol 两种类型的属性,如果我们使用的是任何其他类型值作为属性名,最后都会被转为字符串。比如这里的 [objProp],objProp 是个对象,用它创建完 obj 后,再看看,就变成字符串 “[object Object]” 了。
获取属性的方法
为了更好的演示,我们先来定义一个操作对象。
var obj = {
str: 'This is a String property',
[Symbol()]: 'This is a Symbol property'
}
// 再定义一个不可枚举属性
Object.defineProperty(obj, 'unenum', {
value: 'This is a non-enumerable property',
writeable: true,
enumerable: false,
configurable: true
})
Object.defineProperty(obj, Symbol('unenum'), {
value: 'This is a non-enumerable Symbol property',
writeable: true,
enumerable: false,
configurable: true
})
//
Object.setPrototypeOf(obj, { foo: 'bar', [Symbol('foo')]: 'bar' })
这个对象覆盖了下面要说的不同方法之间的区别。包括一个字符串属性和 Symbol 属性,同时还具有一个不可枚举字符串属性和 Symbol 属性。另外,还重置了原型对象,原型对象里包含了一个字符串属性和 Symbol 属性(都是可枚举的)。
下面展示了 obj 的数据结构。
Object.keys/values/entries
这三个方法都是用来获取对象上的属性集合的。只不过,Object.keys 是用来获取属性名集合,Object.values 是用来获取属性值集合,Object.entries 则是用来获取属性键-值对集合的。
Object.keys(obj) // ["str"]
Object.values(obj) // ["This is a String property"]
Object.entries(obj) // [ ["str", "This is a String property"] ]
通过结果可以发现,除了返回结果的不同之外,这三个属性有一个共同点:只处理 obj 自身的可枚举字符串属性。
Object.getOwnPropertyNames(obj)
顾名思义,Object.getOwnPropertyNames(obj) 获取的是对象自身的属性集合。但具体是哪些属性呢?我们看下:
Object.getOwnPropertyNames(obj) // ["str", "unenum"]
由结果可知,返回了 obj 自身的所有字符串属性(包括不可枚举的),但不包括 Symbol 属性。
Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols(obj) 是跟 Object.getOwnPropertyNames(obj) 相对应的,返回 obj 自身的所有 Symbol 属性(包括不可枚举的)。
Object.getOwnPropertySymbols(obj) // [Symbol(), Symbol(unenum)]
由结果可知,返回了 obj 自身的所有 Symbol 属性(包括不可枚举的),但不包括字符串属性。
Reflect.ownKeys(obj)
Reflect.ownKeys(obj) 可以看做是 Object.getOwnPropertyNames(obj) + Object.getOwnPropertySymbols(obj),即获得 obj 自身的所有属性集合。
Reflect.ownKeys(obj) // ["str", "unenum", Symbol(), Symbol(unenum)]
for-in
再来看看 for-in 语句遍历对象的结果为何。
for (let prop in obj) {
console.log(prop) // "str" -> "foo"
}
由此可见:for-in 返回的是对象自身及所在原型链上的所有可枚举字符串属性。
将 for-in 语句配合 obj.hasOwnProperty(prop) 方法一起使用,就能得到跟 Object.keys/values/entries 方法一样的效果——即返回对象自身的可枚举字符串属性。
for (let prop in obj) {
if (obj.hasOwnProperty(prop)) {
console.log({ key: prop, value: obj[prop], pair: [prop, obj[prop]] })
}
}
// {key: "str", value: "This is a String property", pair: ["str", "This is a String property"] }
总结
方法 返回值 备注
Object.keys/values/entries 对象自身的可枚举字符串属性
Object.getOwnPropertyNames(obj) 对象自身的所有可枚举、不可枚举的字符串属性
Object.getOwnPropertySymbols(obj) 对象自身的所有可枚举、不可枚举的 Symbol 属性
Reflect.ownKeys(obj) 对象自身的所有可枚举、不可枚举的字符串属性、Symbol 属性。 等同于 Object.getOwnPropertyNames(obj) + Object.getOwnPropertySymbols(obj) 的效果。
for (let prop in obj) {} 对象自身及所在原型链上的所有可枚举字符串属性