加入收藏 | 设为首页 | 会员中心 | 我要投稿 汽车网 (https://www.0577qiche.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 教程 > 正文

ES6+ Object.keys()解析

发布时间:2023-03-27 08:48:03 所属栏目:教程 来源:
导读:我们知道迭代对象可以使用 for...in 循环来做,但 for...in 循环会枚举其原型链上的属性,这使得我们在遍历时需要判断是不是原型链属性。Object.keys() 可以接受一个对象返回一个可枚举的数组,数组中的元素的排列顺
我们知道迭代对象可以使用 for...in 循环来做,但 for...in 循环会枚举其原型链上的属性,这使得我们在遍历时需要判断是不是原型链属性。Object.keys() 可以接受一个对象返回一个可枚举的数组,数组中的元素的排列顺序和使用 for...in 循环遍历返回的顺序是一致的。
Object.keys() 在 ES5 中就有此方法,但是在设计上存在一定的缺陷,ES6 对其底层做了重大的更新。比如:在 ES5 中,如果此方法的参数不是对象(而是一个原始值),那么它会抛出 TypeError。在 ES2015 中,非对象的参数将被强制转换为一个对象。

// ES5 代码
Object.keys("imooc");  // TypeError: "imooc" is not an object
// ES6 代码
Object.keys("imooc");  // ["0", "1", "2", "3", "4"]
现在的浏览器已经基本都支持 ES6 的结果了,下面我们来系统性地认识一下 Object.keys()。

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

语法使用:

Object.keys(obj)
参数解释:

参数    描述
obj    要返回其枚举自身属性的对象。

用于对象时返回对象键值作为数组:

var obj =  {
    name:  'imooc',
    type:  'ES6 Wiki'
}
console.log(Object.keys(obj));
// ["name", "type"]
用于数组类型:

var arr = ['a',  'b',  'c'];
console.log(Object.keys(arr));
// console: ['0', '1', '2']
也可以用于类数组中:

var obj =  {  :  'a',  :  'b',  :  'c'  };
console.log(Object.keys(obj));  // ['0', '1', '2']
键值是数字和字符串混合时,会先进行数值的排序,然后再按添加的顺序排列字符串:

var obj =  {  name:  'imooc',  :  'a',  :  'b',  age:    };
console.log(Object.keys(obj));
// ["3", "10", "name", "age"]
Object.keys() 不能获取不可枚举属性:

// 创建一个obj对象带有一个不可枚举属性
var obj =  Object.create({},  {
    getFoo:  {
        value:  function  ()  {  return  this.foo;  }
    }
});
obj.foo =  ;
console.log(Object.keys(obj));  // ['foo']

在说自动排序问题前,我们先来看下三个例子:

var obj1 =  {:  '九十九',  :  '五',  :  '七'}
Object.keys(obj1) // ["5", "7", "99"]
var obj2 =  {c:  'z',  a:  'x',  b:  'y'}
Object.keys(obj2) // ["c", "a", "b"]
var obj3 =  {  name:  'imooc',  :  'a',  :  'b',  age:    };
Object.keys(obj3);  // ["3", "10", "name", "age"]
上面的例子可以看出当键值是数字时返回的值会自动排序,即使在混合情况下也会先进行排序后把数字项放在数组中前面,而键值对是字符串时则不会被排序。那当 Object.keys() 被调用时内部都发生了什么呢?

通过查阅 ECMA262 规范知道,Object.keys 在内部会根据对象的属性名 key 的类型进行不同的排序逻辑。分三种情况:

如果属性名的类型是 Number,那么 Object.keys 返回值是按照 key 从小到大排序;
如果属性名的类型是 String,那么 Object.keys 返回值是按照属性被创建的时间升序排序;
如果属性名的类型是 Symbol,那么逻辑同 String 相同。
那内部到底发生了什么呢?

在 Object.keys() 调用时会根据传入的参数进行类型转换,转换为 Object 类型的值:

参数类型    结果
Undefined    抛出 TypeError
Null    抛出 TypeError
Boolean    返回一个新的 Boolean 对象
Number    返回一个新的 Number 对象
String    返回一个新的 String 对象
Symbol    返回一个新的 Symbol 对象
Object    直接将 Object 返回
实例:

// 参数是undefined或null
Object.keys(undefined) // Uncaught TypeError: Cannot convert undefined or null to object
// 参数是数值
Object.keys() // []
// 参数是字符串
Object.keys('imooc') // ["0", "1", "2", "3", "4"]

上面我们说到了 Object.keys() 会对参数做类型转换,在获取属性的时候会调用内部方法 EnumerableOwnProperties ( O, kind ) 来计算对象上所有可枚举的属性 ownKeys,这里的 ownKeys 类型时 list 类型,只用于内部实现。

然后声明变量用于存放遍历对象后得到的属性集合 properties,properties 也是 List 类型,循环对象的 ownKeys 将每个元素添加到 properties 列表中。最后返回 properties。

为什么会对数值进行排序,是因为在调用 EnumerableOwnProperties(O, kind) 方法执行时,又会调用 OrdinaryOwnPropertyKeys(O) ,对于不同类型的属性,会按不同的顺序放入 properties 属性列表中:

先处理类型为数值的属性,从小到大放到属性列表中;
再处理类型为字符串的属性,按该属性的创建顺序,放到属性列表中;
最后处理类型为 Symbol 的属性,按创建顺序,放到属性列表中。
这样就知道为什么会对数值进行排序了,是 ECMA262 中 OrdinaryOwnPropertyKeys(o) 规定的。其原因是 OrdinaryOwnPropertyKeys(o) 内部方法不只是给 Object.keys() 使用的,是通用的规则。
最后将 properties 列表转化为数组就得到了 Object.keys() 的结果。

本节主要学习了 Object.keys() 方法用于获取对象上可枚举属性,并返回属性的数组,数组中的元素的排列顺序和使用 for...in 循环遍历返回的顺序是一致的。这里需要注意的是,如果对象上的属性是数值时,会被排序。

(编辑:汽车网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章