我们先来看看在 MDN[6] 上关于 Object.keys()
的描述:
Object.keys()
方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
emmm… 并没有直接告诉我们输出顺序是什么,不过我们可以看看上面的 Polyfill[7] 是怎么写的:
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable(‘toString’),
dontEnums = [
‘toString’,
‘toLocaleString’,
‘valueOf’,
‘hasOwnProperty’,
‘isPrototypeOf’,
‘propertyIsEnumerable’,
‘constructor’
],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== ‘object’ && typeof obj !== ‘function’ || obj === null) throw new TypeError(‘Object.keys called on non-object’);
var result = [];
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (hasDontEnumBug) {
for (var i=0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
}
}
return result;
}
})()
};
其实就是利用 for...in
来进行遍历,接下来我们可以再看看关于 for…in[8] 的文档,然而里面也没有告诉我们顺序是怎样的。
既然 MDN 上没有,那我们可以直接看 ECMAScript 规范,通常 MDN 上都会附上关于这个 API 的规范链接,我们直接点开最新(Living Standard)的那个,下面是关于 Object.keys 的规范定义[9]:
When the keys function is called with argument O, the following steps are taken:
- Let obj be ? ToObject[10](O).
- Let nameList be ? EnumerableOwnPropertyNames[11](obj, key).
- Return CreateArrayFromList[12](nameList).
对象属性列表是通过 EnumerableOwnPropertyNames
获取的,这是它的规范定义[9]:
The abstract operation EnumerableOwnPropertyNames takes arguments O (an Object) and kind (key, value, or key+value). It performs the following steps when called:
- Let ownKeys be ? O.[OwnPropertyKeys].
- Let properties be a new empty List.