重学JS | 数组遍历的 7 种方法及兼容性处理 (polyfill)

468 阅读1分钟

这是我参与更文挑战的第2天,活动详情查看: 更文挑战

[重学JavaScript系列文章连载中...]

数组的遍历在数组的所有操作中应该是最频繁的,这里总结下7中常见的遍历方法。同时,通过polyfill理解每个函数的内部实现。

1. 最原始的for循环

const arr = [1,2,3]
for(let i=0;i<arr.length;i++){
  console.log(arr[i])
}

2. 基于forEach()函数的方法

const arr = [1,2,3]
arr.forEach(function(element,index,array){
	console.log(element)
})

forEach()函数是ES5中新增的特性,可能不兼容只支持低版本JS的浏览器,因此提供个pollyfill。

Array.prototype.forEach = Array.prototype.forEach || function(fn,context){
  // 通过for循环,在循环中判断this对象,即数组本身是否包含遍历的索引。
  // 包含,则利用call()函数去调用回调函数,传入回调函数所需的参数。
  if(typeof fn==='function'){
    for(var k=0,length=this.length;k<length;k++){
    	Object.prototype.hasOwnProperty.call(this,k) && fn.call(context,this[k],k,this)
    }
  }
}

3. 基于map()函数的方法

map()在数据遍历中,将数组中的每个元素做处理,得到新的元素。需要注意的是回调函数需要通过return返回处理后的值,否则会返回undefined。

const arr = [1,2,3]
const arr1 = arr.map(function(element){
	return element*2
})
console.log(arr1)  // [2,4,6]

同forEach()函数一样,map()同样需要提供polyfill。

Array.prototype.map = Array.prototype.map || function(fn,context){
	var arr = []
  if(typeof fn==='function'){
    for(var k=0,length=this.length;k<length;k++){
  	  if(Object.prototype.hasOwnProperty.call(this,k)){
    	   arr.push(fn.call(context,this[k],k,this))
      }
    }
  }
  return arr
}

4. 基于filter()函数的方法

filter()函数用于过滤出满足条件的数据,返回一个新的数组,不会改变原来的数组。

const arr = [1,2,3,4]
const filterFn = function(element){
	return element>2
}
const arr1 = arr.filter(filterFn)  // [3,4]

polyfill代码如下:

Array.prototype.filter = Array.prototype.filter || function(fn,context){
	var arr = [];
  if(typeof fn==='function'){
    for(var k=0,length=this.length;k<length;k++){
  	  if(Object.prototype.hasOwnProperty.call(this,k)){
        // 通过判断返回值是否为true来决定是否push到新数组
        fn.call(context,this[k],k,this) && arr.push(this[k])
      }
    }
  }
  return arr
}

5. 基于some()和every()函数的方法

some()函数只要数组中某个元素满足条件就返回true,而every()函数需要数组中的每个元素都满足条件时才返回true。

function isBig(element,index,array){
	return element>2
}

const passed1 = [1,2,3,4].some(isBig)   // true
const passed2 = [1,2,3,4].every(isBig)  // false

some()函数的pollyfill如下:

Array.prototype.some = Array.prototype.some || function(fn,context){
  var passed = false
  if(typeof fn==='function'){
  	for(var k=0,length=this.length;k<length;k++){
    	if(passed===true) break; // 有返回值true,直接跳出循环
      passed = Object.prototype.hasOwnProperty.call(this,k)?
        !! fn.call(context,this[k],k,this):passed
    }
  } 
  return passed
}

every()函数的pollyfill如下:

Array.prototype.every = Array.prototype.every || function(fn,context){
  var passed = true
  if(typeof fn==='function'){
  	for(var k=0,length=this.length;k<length;k++){
    	if(passed===false) break; // 有返回值false,直接跳出循环
      passed = Object.prototype.hasOwnProperty.call(this,k)?
        !! fn.call(context,this[k],k,this):passed
    }
  } 
  return passed
}

6. 基于reduce()函数的方法

reduce()函数主要作用是做累加处理,即接收一个函数作为累加器。

arr.reduce(callback[,initialValue]);

callback接收四个参数:accumulator、currentValue、currentIndex、array

  1. initialValue:作为callback的第一个参数值,若未设置,则默认使用数组的第一个元素值。

  2. accumulator: 表示上一次调用累加器的返回值,或设置的initialValue。

let arr = [1,2,3]
let add = function(accumulator,currentValue){
	return accumulator+currentValue
}
let sum = arr.reduce(add,0)  // 6

reduce()函数的polyfill如下:

Array.prototype.reduce = Array.prototype.reduce || function(callback,initialValue){
  var previous = initialValue,k = 0, length = this.length;
  if(typeof initialValue === 'undefined'){
  	previous = this[0]
    k = 1
  }
  if(typeof callback === 'function'){
  	for(k;k<length;k++){
    	this.hasOwnProperty(k) && (previous = callback(previous,this[k],k,this))
    }
  }
  return previous
}

7. 基于find()函数的方法

find()函数用于数组遍历的过程中,找到第一个满足条件的元素值时,则直接返回该元素值;如果都不满足条件,则返回undefined。

let arr = [1,2,3]
let value = arr.find(function(element,index,array){
	return element>2
})  // 3

find()函数的polyfill如下:

Array.prototype.find = Array.prototype.find || function(fn,context){
	if(typeof fn==='function'){
  	for(var k = 0,length = this.length;k < length;k++){
    	if(fn.call(context,this[k],k,this)){
      	return this[k]
      }
    }
  }
  return undefined
}

8. 总结

至此我们完成了7个与函数遍历相关的方法,以及它们的polyfill实现。