Object.keys()
这个方法获取的是「自身」「可枚举」 的属性的key, 不可枚举及从原型继承来的属性的 key 不可获得,返回值为 key 组成的数组。
Object.getOwnPropertyNames()
这个方法获取的是自身属性的 key, 包括可枚举和不可枚举属性的 key,返回值为 key 组成的数组。
for in
遍历自身及原型链上继承来的可枚举属性
上面介绍的这几项无法获取到 Symbol 值的 key,但可以通过 Object.getOwnPropertySymbols() 获取自身的 Symbol 值的key,这里不考虑 Symbol 的情况。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const testObj = { 1: 'one', two: 2, three: 3, four: 4, 5: 'five', }; Object.defineProperty(testObj, '6', { value: 'six', enumerable: false, }); Object.prototype.seven = 7; console.log('---- Object.keys ----'); console.log(Object.keys(testObj));
console.log('---- Object.getOwnPropertyNames ----'); console.log(Object.getOwnPropertyNames(testObj));
console.log('---- for in ----'); for(let key in testObj) console.log(key);
|
打印结果如下:

分析并发现问题
testObj 的属性中, key 值为 ‘6’ 的为不可枚举属性,key 值为 ‘seven’ 的为原型链上的属性。Object.keys 和 Object.getOwnPropertyNames 返回的都是自身的属性,区别在于 getOwnPropertyNames 返回结果中包含不可枚举的属性,for in 遍历自身及原型链上可枚举的属性。
从打印的结果我发现几个问题:
- key 的顺序为什么不是创建的顺序
- for … in 如何只遍历自身属性的 key
- 如何得到对象自身不可枚举的 key
1. key 的顺序问题
大多数浏览器的新版本按照这样的方式处理: 将整数型的key排在前面,不是整数型的key按照创建的顺序排(整数型指变为整数再从整数变回来,改变前后完全相同的数), 例如 “+1” -> 1 -> ‘1’, 则 +1 不是整数型key).
我们可以改下上面的 testObj,再次进行测试。
1 2 3 4 5 6 7 8 9 10 11
| const testObj = { 1: 'one', two: 2, three: 3, four: 4, 5: 'five', }; console.log(Object.keys(testObj)); delete testObj['two'] testObj['two'] = '2'; console.log(Object.keys(testObj));
|

但在一些老的浏览器并不是按照这样的方式处理的,所以不同浏览器存在差异,如果想对顺序有特别的要求,建议还是对返回的存储key的数组进行处理后,使其按特定顺序输出。
2. for … in 如何只遍历自身属性的 key
可以使用 *hasOwnProperty *进行判断过滤。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const testObj = { 1: 'one', two: 2, three: 3, four: 4, 5: 'five', }; Object.prototype.seven = 7; console.log('---- for in ----'); for(let key in testObj) { if (testObj.hasOwnProperty(key)) { console.log(key); } }
|

3.如何得到对象自身不可枚举的 key
不考虑 Symbol 的key,Object.getOwnPropertyNames() 得到的 key 去掉 Object.keys() 得到的 key 就是不可枚举的 key。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const testObj = { 1: 'one', two: 2, three: 3, four: 4, 5: 'five', }; Object.defineProperty(testObj, '6', { value: 'six', enumerable: false, }); console.log(testObj); const allKeys = Object.getOwnPropertyNames(testObj); const enumerableKeys = Object.keys(testObj); const unEnumerableKeys = allKeys.filter(key => enumerableKeys.indexOf(key) === -1); console.log('unEnumerableKeys:', unEnumerableKeys);
|
这里 chrome 浏览器有个奇怪的 bug, 去掉第12行的打印在 Chrome 74.0.3729.169(正式版本) (64 位)通过 getOwnPropertyNames 无法得到不可枚举的key, safari 测试正常。
