首页IT科技objection(Object.keys 诡异特性示例详解)

objection(Object.keys 诡异特性示例详解)

时间2025-05-02 12:51:42分类IT科技浏览5115
导读:先从‘诡异’的问题入手 例1: 纯Number类型的属性...

先从‘诡异’的问题入手

例1: 纯Number类型的属性
const obj = { 1: 1, 6: 6, 3: 3, 2: 2 } console.log(keys, Object.keys(obj)) // [1, 2, 3, 6]

返回的key为什么自动按照升序排序了?

例2: 纯String类型的属性
const obj2 = { a: a, c: c, f: f, b: b, } console.log(Object.keys(obj2)) // [a, c, f, b]

这里为什么又不自动排序了?

看到这里是不是觉得很懵?话不多说            ,我们先查文档                  ,看看mdn上对Object.keys的描述:

Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组      ,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致             。

emm            ,然而它并没有说到底是按哪种顺序返回的                  。

探索

既然文档上找不到                  ,那我们就一步一步来慢慢研究

Object.keys的polyfill的实现

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; } })() };

从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
console.log(Object.keys(123)) // []

返回的是空数组            ,这是因为new Number(123)并没有可提取的属性

String
console.log(Object.keys(123)) // [ 0, 1, 2 ]

字符串之所以返回的不是空数组,是因为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 类型索引按属性创建时间以升序排序

合法数组索引指的是正整数            ,负数或者浮点数一律当做字符串处理                  。严格来说对象属性没有数字类型的                  ,无论是数字还是字符串      ,都会被当做字符串来处理            。

看题

const obj = {} obj[-1] = -1 obj[1] = 1 obj[1.1] = 1.1 obj[2] = 2 obj[c] = c obj[b] = b obj[a] = a obj[2] = 2 obj[Symbol(1)] = Symbol(1) obj[Symbol(a)] = Symbol(a) obj[Symbol(b)] = Symbol(b) obj[d] = d console.log(Object.keys(obj))

经过上面对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版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
sass me(sass @extend(继承)指令详解) mac 更新错误(macOS 10.15.6 补充更新发布 重要的错误修复和改进)