基本概念


可枚举(enumerable)

可枚举性(enumerable)用来控制所描述的属性,是否将被包括在for…in循环之中。具体来说,如果一个属性的enumerable为false,下面三个操作不会取到该属性。

  • for..in循环
  • Object.keys方法
  • JSON.stringify方法
  1. var o = {a:1, b:2};
  2. o.c = 3;
  3. Object.defineProperty(o, 'd', {
  4. value: 4,
  5. enumerable: false
  6. });
  7. o.d
  8. // 4
  9. for( var key in o ) console.log( o[key] );
  10. // 1
  11. // 2
  12. // 3
  13. Object.keys(o) // ["a", "b", "c"]
  14. JSON.stringify(o // => "{a:1,b:2,c:3}"

上面代码中,d属性的enumerablefalse,所以一般的遍历操作都无法获取该属性,使得它有点像“秘密”属性,但还是可以直接获取它的值。
至于for...in循环和Object.keys方法的区别,在于前者包括对象继承自原型对象的属性,而后者只包括对象本身的属性。如果需要获取对象自身的所有属性,不管enumerable的值,可以使用Object.getOwnPropertyNames方法

小结

方法 适用范围 描述
for…in 数组,对象 获取可枚举的实例和原型属性名
Object.keys() 数组,对象 返回可枚举的实例属性名组成的数组
Object.getPropertyNames() 数组,对象 返回除原型属性以外的所有属性(包括不可枚举的属性)名组成的数组
for…of 可迭代对象Arry,Map,Set,argument等 返回属性值

数组和对象在遍历的时候,都有哪些方法?首先列举数组的遍历方法

数组遍历方法


for 语句

  1. var arr = [1,2,4,6]
  2. for(var i = 0, len = arr.length; i < len; i++){
  3. console.log(arr[i])
  4. }

这是标准for 循环的写法也是最传统的语句,字符串也支持,定义一个变量i作为索引,以跟踪访问的位置,len是数组的长度,条件就是i不能超过len。

forEach 语句

  1. var arr = [1,5,8,9]
  2. arr.forEach(function(item) {
  3. console.log(item);
  4. })

forEach 方法对数组的每个元素执行一次提供的CALLBACK函数,forEach是一个数组方法,可以用来把一个函数套用在一个数组中的每个元素上,为每个数组元素执行callback函数只可用于数组.遍历一个数组让数组每个元素做一件事情.那些已删除(使用delete方法等情况)或者未初始化的项将被跳过(但不包括那些值为 undefined 的项)(例如在稀疏数组上);不像map() 或者reduce() ,它总是返回 undefined值,并且不可链式调用。典型用例是在一个链的最后执行副作用。

for-in 语句

  1. var obj = {
  2. name: 'test',
  3. color: 'red',
  4. day: 'sunday',
  5. number: 5
  6. }
  7. for (var key in obj) {
  8. console.log(obj[key])
  9. }

一般会使用for-in来遍历对象的属性的,不过属性需要 enumerable,才能被读取到. for-in 循环只遍历可枚举属性。一般常用来遍历对象,包括非整数类型的名称和继承的那些原型链上面的属性也能被遍历。像 Array和 Object使用内置构造函数所创建的对象都会继承自Object.prototype和String.prototype的不可枚举属性就不能遍历了。

for-of 语句

  1. var arr = [{name:'bb'},5,'test']
  2. for (item of arr) {
  3. console.log(item)
  4. }

for-of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。只要是一个iterable的对象,就可以通过for-of来迭代。

for-of 和 for-in 的区别

for-in 语句以原始插入顺序迭代对象的可枚举属性。for-in会把继承链的对象属性都会遍历一遍,所以会更花时间.
for-of 语句只遍历可迭代对象的数据。

map 方法(不改变原数组)

  1. var arr = [1,2,3]
  2. var firearr = arr.map(current => current * 5)

map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值(包括 undefined)组合起来形成一个新数组。 callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。让数组通过某种计算产生一个新数组,影射成一个新的数组。

filter 方法(不改变原数组)

  1. var arr = [2,3,4,5,6]
  2. var morearr = arr.filter(function (number) {
  3. return number > 3
  4. })

filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或 等价于 true 的值 的元素创建一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。筛选出过滤出数组中符合条件的项,组成新数组。

reduce 方法

  1. var wallets = [4,7.8,3]
  2. var totalMoney = wallets.reduce( function (countedMoney, wallet) {
  3. return countedMoney + wallet.money;
  4. }, 0)

让数组中的前项和后项做某种计算,并累计最终值。

every 方法

  1. var arr = [1,2,3,4,5]
  2. var result = arr.every(function (item, index) {
  3. return item > 0
  4. })

every 方法为数组中的每个元素执行一次 callback 函数,直到它找到一个使 callback 返回 false(表示可转换为布尔值 false 的值)的元素。如果发现了一个这样的元素,every 方法将会立即返回 false。否则,callback 为每一个元素返回 true,every 就会返回 true。检测数组中的每一项是否符合条件,如果每一项都符合条件,就会返回true,否则返回false,有点像遍历数组且操作callback。只会为那些已经被赋值的索引调用。不会为那些被删除或从来没被赋值的索引调用。

some 方法

  1. var arr = [1,2,3,4,5]
  2. var result = arr.some(function (item,index) {
  3. return item > 3
  4. })

some 为数组中的每一个元素执行一次 callback 函数,直到找到一个使得 callback 返回一个“真值”(即可转换为布尔值 true 的值)。如果找到了这样一个值,some 将会立即返回 true。否则,some 返回 false。callback 只会在那些”有值“的索引上被调用,不会在那些被删除或从来未被赋值的索引上调用。检查数组中是否有某些项符号条件,如果有一项就返回true,否则返回false,有点像遍历数组或者操作。

对象遍历方法


Object.keys() 方法

  1. //数组
  2. var a=["a","b","c"]
  3. Object.keys(a) //输出["0","1","2"]
  4. //对象
  5. var obj={a:1,b:2,c:3}
  6. Object.keys(obj) //输出["a","b","c"]
  7. //不可枚举属性
  8. var obj1={
  9. {},
  10. {getFoo:function(){value:function(){return this.foo}}}
  11. }
  12. obj1.foo="1"
  13. Object.keys(obj1) //输出foo

Object.keys(obj) 会返回一个由传入对象的可枚举属性组成的数组,数组名的排列顺序和使用for…in…循环遍历该对象返回的顺序一致。
区别: for…in….循环还会枚举其原型链上的属性。

for-in 方法

  1. var obj = {"name":"Poly", "career":"it"}
  2. Object.defineProperty(obj, "age", {value:"forever 18", enumerable:false});
  3. Object.prototype.protoPer1 = function(){console.log("proto");};
  4. Object.prototype.protoPer2 = 2;
  5. console.log("For In : ");
  6. for(var a in obj) console.log(a); //For In: name career protoPer1 protoPer2

主要用于遍历对象的可枚举属性,包括自有属性、继承自原型的属性。

Object.getOwnProperty 方法

  1. var obj = {"name":"Poly", "career":"it"}
  2. Object.defineProperty(obj, "age", {value:"forever 18", enumerable:false});
  3. Object.prototype.protoPer1 = function(){console.log("proto");};
  4. Object.prototype.protoPer2 = 2;
  5. console.log("Object.getOwnPropertyNames: ");
  6. console.log(Object.getOwnPropertyNames(obj)); // "name" "career" "age"

用于返回对象的自有属性,包括可枚举和不可枚举的。

对比遍历速度


对比这里我使用了jsPerf平台进行测试。

  1. // 一个是空数组
  2. var nullarr = new Array(10000) // [undefined,undefined,...undefined]
  3. // 另一个带不同类型的数据的数组
  4. var dataarr = []
  5. for(var i = 0; i < 10000; i++){
  6. if (i % 2 ===0) {
  7. dataarr[i] = i.toString()
  8. } else {
  9. dataarr[i = i
  10. }
  11. }
  12. dataarr // [1,'2',3...,10000]

image.png

速度排序,for > for-of > forEach > filter > map > for-in

干货

image.png