ES6+ Object.keys()
1. 前言
我們知道迭代對(duì)象可以使用 for...in
循環(huán)來(lái)做,但 for...in
循環(huán)會(huì)枚舉其原型鏈上的屬性,這使得我們?cè)诒闅v時(shí)需要判斷是不是原型鏈屬性。Object.keys()
可以接受一個(gè)對(duì)象返回一個(gè)可枚舉的數(shù)組,數(shù)組中的元素的排列順序和使用 for...in
循環(huán)遍歷返回的順序是一致的。
Object.keys()
在 ES5 中就有此方法,但是在設(shè)計(jì)上存在一定的缺陷,ES6 對(duì)其底層做了重大的更新。比如:在 ES5 中,如果此方法的參數(shù)不是對(duì)象(而是一個(gè)原始值),那么它會(huì)拋出 TypeError。在 ES2015 中,非對(duì)象的參數(shù)將被強(qiáng)制轉(zhuǎn)換為一個(gè)對(duì)象。
// ES5 代碼
Object.keys("imooc"); // TypeError: "imooc" is not an object
// ES6 代碼
Object.keys("imooc"); // ["0", "1", "2", "3", "4"]
現(xiàn)在的瀏覽器已經(jīng)基本都支持 ES6 的結(jié)果了,下面我們來(lái)系統(tǒng)性地認(rèn)識(shí)一下 Object.keys()
。
2. 方法詳情
2.1 基本語(yǔ)法
Object.keys()
方法會(huì)返回一個(gè)由一個(gè)給定對(duì)象的自身可枚舉屬性組成的數(shù)組,數(shù)組中屬性名的排列順序和正常循環(huán)遍歷該對(duì)象時(shí)返回的順序一致 。
語(yǔ)法使用:
Object.keys(obj)
參數(shù)解釋?zhuān)?/strong>
參數(shù) | 描述 |
---|---|
obj | 要返回其枚舉自身屬性的對(duì)象。 |
2.2 基本實(shí)例
用于對(duì)象時(shí)返回對(duì)象鍵值作為數(shù)組:
var obj = {
name: 'imooc',
type: 'ES6 Wiki'
}
console.log(Object.keys(obj));
// ["name", "type"]
用于數(shù)組類(lèi)型:
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr));
// console: ['0', '1', '2']
也可以用于類(lèi)數(shù)組中:
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // ['0', '1', '2']
鍵值是數(shù)字和字符串混合時(shí),會(huì)先進(jìn)行數(shù)值的排序,然后再按添加的順序排列字符串:
var obj = { name: 'imooc', 10: 'a', 3: 'b', age: 7 };
console.log(Object.keys(obj));
// ["3", "10", "name", "age"]
Object.keys()
不能獲取不可枚舉屬性:
// 創(chuàng)建一個(gè)obj對(duì)象帶有一個(gè)不可枚舉屬性
var obj = Object.create({}, {
getFoo: {
value: function () { return this.foo; }
}
});
obj.foo = 1;
console.log(Object.keys(obj)); // ['foo']
3. 自動(dòng)排序問(wèn)題
在說(shuō)自動(dòng)排序問(wèn)題前,我們先來(lái)看下三個(gè)例子:
var obj1 = {99: '九十九', 5: '五', 7: '七'}
Object.keys(obj1) // ["5", "7", "99"]
var obj2 = {c: 'z', a: 'x', b: 'y'}
Object.keys(obj2) // ["c", "a", "b"]
var obj3 = { name: 'imooc', 10: 'a', 3: 'b', age: 7 };
Object.keys(obj3); // ["3", "10", "name", "age"]
上面的例子可以看出當(dāng)鍵值是數(shù)字時(shí)返回的值會(huì)自動(dòng)排序,即使在混合情況下也會(huì)先進(jìn)行排序后把數(shù)字項(xiàng)放在數(shù)組中前面,而鍵值對(duì)是字符串時(shí)則不會(huì)被排序。那當(dāng) Object.keys()
被調(diào)用時(shí)內(nèi)部都發(fā)生了什么呢?
通過(guò)查閱 ECMA262 規(guī)范知道,Object.keys
在內(nèi)部會(huì)根據(jù)對(duì)象的屬性名 key
的類(lèi)型進(jìn)行不同的排序邏輯。分三種情況:
- 如果屬性名的類(lèi)型是
Number
,那么Object.keys
返回值是按照key
從小到大排序; - 如果屬性名的類(lèi)型是
String
,那么Object.keys
返回值是按照屬性被創(chuàng)建的時(shí)間升序排序; - 如果屬性名的類(lèi)型是
Symbol
,那么邏輯同String
相同。
那內(nèi)部到底發(fā)生了什么呢?
3.1 將參數(shù)轉(zhuǎn)換為對(duì)象
在 Object.keys()
調(diào)用時(shí)會(huì)根據(jù)傳入的參數(shù)進(jìn)行類(lèi)型轉(zhuǎn)換,轉(zhuǎn)換為 Object 類(lèi)型的值:
參數(shù)類(lèi)型 | 結(jié)果 |
---|---|
Undefined | 拋出 TypeError |
Null | 拋出 TypeError |
Boolean | 返回一個(gè)新的 Boolean 對(duì)象 |
Number | 返回一個(gè)新的 Number 對(duì)象 |
String | 返回一個(gè)新的 String 對(duì)象 |
Symbol | 返回一個(gè)新的 Symbol 對(duì)象 |
Object | 直接將 Object 返回 |
實(shí)例:
// 參數(shù)是undefined或null
Object.keys(undefined) // Uncaught TypeError: Cannot convert undefined or null to object
// 參數(shù)是數(shù)值
Object.keys(123) // []
// 參數(shù)是字符串
Object.keys('imooc') // ["0", "1", "2", "3", "4"]
上面的代碼中,參數(shù)是數(shù)值時(shí)為什么會(huì)返回空數(shù)組呢?是因?yàn)閿?shù)值轉(zhuǎn)換為對(duì)象時(shí)沒(méi)有可提取的屬性,而字符串在 ES5 時(shí)會(huì)報(bào)錯(cuò),ES6 進(jìn)行了修復(fù),因?yàn)?String 對(duì)象有可提取的屬性??聪旅鎯蓮垐D:
3.2 獲取屬性列表
上面我們說(shuō)到了 Object.keys()
會(huì)對(duì)參數(shù)做類(lèi)型轉(zhuǎn)換,在獲取屬性的時(shí)候會(huì)調(diào)用內(nèi)部方法 EnumerableOwnProperties ( O, kind )
來(lái)計(jì)算對(duì)象上所有可枚舉的屬性 ownKeys
,這里的 ownKeys
類(lèi)型時(shí) list
類(lèi)型,只用于內(nèi)部實(shí)現(xiàn)。
然后聲明變量用于存放遍歷對(duì)象后得到的屬性集合 properties
,properties
也是 List 類(lèi)型,循環(huán)對(duì)象的 ownKeys
將每個(gè)元素添加到 properties
列表中。最后返回 properties
。
為什么會(huì)對(duì)數(shù)值進(jìn)行排序,是因?yàn)樵谡{(diào)用 EnumerableOwnProperties(O, kind)
方法執(zhí)行時(shí),又會(huì)調(diào)用 OrdinaryOwnPropertyKeys(O)
,對(duì)于不同類(lèi)型的屬性,會(huì)按不同的順序放入 properties
屬性列表中:
- 先處理類(lèi)型為數(shù)值的屬性,從小到大放到屬性列表中;
- 再處理類(lèi)型為字符串的屬性,按該屬性的創(chuàng)建順序,放到屬性列表中;
- 最后處理類(lèi)型為
Symbol
的屬性,按創(chuàng)建順序,放到屬性列表中。
這樣就知道為什么會(huì)對(duì)數(shù)值進(jìn)行排序了,是 ECMA262 中 OrdinaryOwnPropertyKeys(o)
規(guī)定的。其原因是 OrdinaryOwnPropertyKeys(o)
內(nèi)部方法不只是給 Object.keys()
使用的,是通用的規(guī)則。
最后將 properties
列表轉(zhuǎn)化為數(shù)組就得到了 Object.keys()
的結(jié)果。
4. 小結(jié)
本節(jié)主要學(xué)習(xí)了 Object.keys()
方法用于獲取對(duì)象上可枚舉屬性,并返回屬性的數(shù)組,數(shù)組中的元素的排列順序和使用 for...in
循環(huán)遍歷返回的順序是一致的。這里需要注意的是,如果對(duì)象上的屬性是數(shù)值時(shí),會(huì)被排序。