JavaScript的对象遍历

引言

遍历对象是平常工作中很常见的一个操作,几乎是日常操作,但是遍历对象真的是一件很容易的事情么,显然不是的。

常用的方式

for...in

for (variable in object) {...}

这个是一个很常见的用法,相信每个人顺手都可以写出来。但是这里需要主要的是一段这个遍历的定义

for...in语句以任意顺序遍历一个对象自有的、继承的、可枚举的、非Symbol的属性。对于每个不同的属性,语句都会被执行。

一个一个词抠吧。

对象自有的

如果一个key是对象自有的那么一定可以用obj.hasOwnProperty(prop)的返回值来判断

继承的

这个也很好理解,比如下面的例子

var parent = {a: 1};

function child() {
  this.b = 'b';
}

child.prototype = parent;

var obj = new child();
复制代码

此时由于obj的原型链继承了parent,所以其实obj是有a属性的。换句话说for in会遍历对象原型链上的属性

可枚举的

什么是可枚举的详细的可以看一下这个链接 首先对象的属性分为两种,数据属性如a['b']=1,这个就是数据属性,另一种就是访问器属性,也就是我们用的getter。 这两种属性都有一个特性的[[Enumerable]],这个布尔值代表了这个属性是否可以被枚举。如果一个对象的属性被设定为不可枚举,那么for in并不可以遍历到。可枚举性可以用propertyIsEnumerable来判断。

非Symbol

Symbol是什么这里不展开说了不熟悉的建议看一下es6 symbol symbol可以被用作给某个对象做私有属性,而如果属性值是symbol类型的那么for in也是无法遍历的。

小结

综上可以明确的知道到底对象的哪些属性可以用for in去遍历出来了,坑点在基础和可枚举。数组遍历我们会自然的去用for in,但是大家是否考虑过,数组也是一个对象,为什么我们再用for in的时候不会把数组的长度,length作为一个属性遍历到呢,原因也就是length属性其实是一个不可枚举属性

Object.keys

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

注意点这里和for in有一个很大的区别,就是这个返回的是对象自身可枚举属性组成的数组,不包含继承

var parent = {a: 1};

function child() {
  this.b = 'b';
}

child.prototype = parent;

var obj = new child();
Object.keys(obj);  //['b']
复制代码

getOwnPropertyNames(obj)与getOwnPropertySymbols(obj)

getOwnPropertyNames方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。 getOwnPropertySymbols方法返回一个给定对象自身的所有 Symbol 属性的数组。 关键词,所有的,自身的。这两个方法不受是否可枚举属性的限制,而且是只返回自身的,所以Object.getOwnPropertyNames的返回值一定是包含了Object.keys的返回值

Reflect.ownKeys(obj)

Reflect.ownKeys 方法返回一个由目标对象自身的属性键组成的数组。它的返回值等同于Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))。

for...of

接下来说说另一种遍历的方案。for of 与for in 不同的就是for of是在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。下面还是进入抠关键词的阶段

可迭代对象

什么是可迭代对象?遵循有可迭代协议的对象成为可迭代对象,用人话说就是一个对象如果有[Symbol.iterator],那么他就是可迭代对象。Symbol.iterator是es6提供了 1个内置的 Symbol 值。 iterator简单说就是一个有一个next函数,这个函数执行的返回值一定是一个对象,对象有两个属性done标记迭代是否结束,value标记这次迭代的结果值。

如何用for...of遍历对象

综上所述也就是说给你的要遍历的对象增加一个Symbol.iterator就可以了

拓展运算符

除了上面说的还想再补充一种遍历的场景,对象的拓展运算符,那么对象的拓展运算符究竟是有哪些属性可以被赋值。 自身的,可枚举的。可以看两个例子

var obj = {}
Object.defineProperty(obj, 'key', {
	enumerable: false,
  	configurable: true,
  	writable: true,
  value: "a"
});
b = {...obj};
console.log(b); //{}
复制代码

可以看到不可枚举属性在解构赋值中是不可被赋值的。

var parent = {a: 1};

function child() {
  this.b = 'b';
}

child.prototype = parent;

var obj = new child();
var b = {...obj};  
console.log(b);//{b: 'b'}
复制代码

可以看到继承的属性在解构赋值中是不可被赋值的。

总结

对象的遍历方法很多,但是要根据具体对象属性的特征和应用场景,还有兼容性来选择最适合的遍历方案。

猜你喜欢

转载自blog.csdn.net/weixin_34247155/article/details/91399478
今日推荐