object.keys源码探讨笔记

269 阅读2分钟

之前曾在网上看到使用object.keys的时候,如果对象的key是正整数,那么他就会被进行排序,我很好奇是否是这样,而且如果用其他方法去遍历对象的key是否结果都一样.

那么,先来创建几个对象

let en={
    a:1,
    b:2,
    d:3,
    c:4,
}
let num={
    1:1,
    3:2,
    4:3,
    2:4,
}

那么对象创建完毕了,来试试看遍历它的key

console.log("Object.keys(keys):",Object.keys(en));
​
console.log("Object.getOwnPropertyNames(keys):",Object.getOwnPropertyNames(en));
​
let listEn=[]
for(let key in en){
        listEn.push(key);
}
console.log("listEn:",listEn);
    

使用了三种方法,分别是object.keys,object.getOwnPropertyNames以及for in.

现在,执行一下代码,看看结果如何.

image-20220208101654987.png

看起来很正常,key是字符的情况下是按照创建对象时的属性顺序进行显示的.

那么接下来试试看正整数为key的那部分

image-20220208104113568.png

很神奇,三种方法显示的结果都是一样的,按照正整数顺序展示了,与创建时的顺序无关了.

再进行几个测试

字符数字:

image-20220208104303167.png

数字+字母:

image-20220208104454535.png

无小数浮点数: ** image-20220208104911551.png ** 有小数浮点数:

image-20220208105606320.png

所以只有在key为实际为正整数的情况下,对象内部的属性顺序才会被排序.

什么的问题解决了,接下来是为什么.

答案在 ECMA262规范 中,不过是纯英文,以我英语四级的水平看起来有那么一些折磨,所以我又去百度了一下.

找到了这篇文章 ,然后在ECMA规范中有说到,object.keys的原理,如下图所示

image-20220208111632001.png

image-20220208112726508.png 先将对象转成obj,然后通过Enum...方法获取到属性列表,并赋值给array.

然后getOwnPropertyNames的原理是先将对象转成object,然后使用迭代器一个个遍历出来. image-20220208111902595.png 从上面两个图中可以看到,这两种方法都用到了OwnPropertyKeys,然后发现这个方法就是用来获取属性列表的.

所以我猜测,所有obj的获取属性,最终都是调用以下的OwnPropertyKeys方法. 这就是为什么,用三种方法的结果都是一样的情况,因为最底层的本质都是同一个方法.

image-20220208112658186.png 而关于ownPropertyKeys的各种情况中,关于整数情况的处理如下:

image-20220208113622974.png

image-20220208113608644.png 所以这就是为什么使用正整数的时候,顺序会被重新排序.

顺带一提,以上的排序规则同样适用与下面这几个方法.

  1. Object.entries
  2. Object.values
  3. for...in循环
  4. Object.getOwnPropertyNames
  5. Reflect.ownKeys

初次写这种笔记,倘若有什么问题,还望大佬们指出.