objection(Object.keys 诡异特性示例详解)
先从‘诡异’的问题入手
例1: 纯Number类型的属性返回的key为什么自动按照升序排序了?
例2: 纯String类型的属性这里为什么又不自动排序了?
看到这里是不是觉得很懵?话不多说 ,我们先查文档 ,看看mdn上对Object.keys的描述:
Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
emm ,然而它并没有说到底是按哪种顺序返回的 。
探索
既然文档上找不到 ,那我们就一步一步来慢慢研究
Object.keys的polyfill的实现
从Object.keys的polyfill的实现 ,我们可以发现它内部其实是用for...in来实现的。那我们就可以去查找for...in遍历时的顺序规则 。然而它也并没有介绍遍历的顺序是怎样的 ,那么我们就只能去查找ECMAScript的规范了 。
Object.keys的规范定义
调用ToObject(O)将结果赋值给变量obj
调用EnumerableOwnPropertyNames(obj, "key")将结果赋值给变量nameList
调用CreateArrayFromList(nameList)得到最终的结果
第一步:将参数转换成Object(ToObject(O))
因为Object.keys内部会调用ToObject(O)方法 ,所以它不只是可以接受对象参数 ,还可以接受其它类型的参数 ,下面这张表就是ToObject根据不同类型的值转成Object的映射:
参数类型 结果 Undefined 抛出TypeError Null 抛出TypeError Number 返回一个新的 Number 对象 String 返回一个新的 String 对象 Boolean 返回一个新的 Boolean 对象 Symbol 返回一个新的 Symbol 对象 Object 直接将Object返回我们通常给Object.keys传的参数都会是一个对象 ,但我们也可以来看看其它类型值的返回值会是怎样的?
Number返回的是空数组 ,这是因为new Number(123)并没有可提取的属性
String字符串之所以返回的不是空数组,是因为new String(123)有可以提取的属性
第二步:通过转换后的对象获得属性列表properties 。
(顺序取决于这里)
对象属性列表是通过 EnumerableOwnPropertyNames 获取的 ,其中比较重要的是调用对象的内部方法OwnPropertyKeys获得对象的ownKeys(这些内容可以在ECMAScript规范里面找到 ,就不展开介绍了,我们重点看排序)
The [[OwnPropertyKeys]] internal method of an ordinary object O takes no arguments. It performs the following steps when called:
Return ! OrdinaryOwnPropertyKeys(O).
通过上面的介绍 ,我们可以发现keys的排序取决于 OrdinaryOwnPropertyKeys(O)
翻译过来就是:
创建一个空的列表用于存放 keys 将所有合法的数组索引按升序的顺序存入 将所有字符串类型索引按属性创建时间以升序的顺序存入 将所有 Symbol 类型索引按属性创建时间以升序的顺序存入 返回 keys注意:属性列表properties为List类型(List类型是ECMAScript规范类型)
第三步:将List类型的属性列表properties转换为Array得到最终的结果 。
将List类型的属性列表转换成Array类型非常简单:
先声明一个变量array ,值是一个空数组 循环属性列表,将每个元素添加到array中 将array返回总结
Object.keys返回的对象属性顺序
将所有合法的数组索引按升序排序 将所有字符串类型索引按属性创建时间以升序排序 将所有 Symbol 类型索引按属性创建时间以升序排序合法数组索引指的是正整数 ,负数或者浮点数一律当做字符串处理 。严格来说对象属性没有数字类型的 ,无论是数字还是字符串 ,都会被当做字符串来处理 。
看题
经过上面对Object.key特性的介绍 ,想必大家都不会再搞错Object.keys的输出顺序了吧 。
答案:
[ 1, 2, -1, 1.1, c, b, a, d ]
看到答案很多同学是不是有很多疑问?
如何理解对象属性是正整数还是字符串?
首先我们上面说过合法数组索引指的是正整数 ,负数或者浮点数一律当做字符串处理 。严格来说对象属性没有数字类型的 ,无论是数字还是字符串 ,都会被当做字符串来处理 。
所以上面只有1 ,2 ,2是合法数组索引,但我们知道其实它们都会被转成字符串 ,所以后面的2会将前面的2覆盖 ,然后它们按升序排序。然后负数与浮点数一律当做字符串处理按属性创建时间以升序排序 。这样就可以得到上面的答案了 。
为什么没有Symbol类型?
因为在 EnumerableOwnPropertyNames 的规范中规定了返回值只应包含字符串属性(上面说了数字其实也是字符串)。
我们也可以在MDN上查看关于 Object.getOwnPropertyNames() 的描述 。
Object.getOwnPropertyNames() 方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组 。
所以 Symbol 属性是不会被返回的,如果要返回 Symbol 属性可以用 Object.getOwnPropertySymbols()。
以上就是Object.keys 诡异特性示例详解的详细内容 ,更多关于Object.keys 诡异的资料请关注本站其它相关文章!
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!