Skip to content

通过函数实现数组方法

通过实现数组方法来让我们对数组方法的认识更加加深一些。

测试函数

我们先创建个函数,让我们更好的看到函数的输入输出等等。

js
// 帮助函数
function logOperation(operationName, array, callback) {
  const input = [...array]
  const result = callback(array)

  console.log({
    operation: operationName,
    arrayBefore: input,
    arrayAfter: array,
    mutates: mutatesArray(input, array), // shallow check
    result
  })
}

function mutatesArray(firstArray, secondArray) {
  if (firstArray.length !== secondArray.length) {
    return true
  }

  for (let index = 0; index < firstArray.length; index += 1) {
    if (firstArray[index] !== secondArray[index]) {
      return true
    }
  }
  return false
}

forEach

  • 作用:对数组的每个元素执行一次提供的函数。

实现

js
function forEach(array, callback) {
  const length = array.length

  for (let index = 0; index < length; index++) {
    const value = array[index]
    callback(value, index, array)
  }
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('forEach', arr, (array) => forEach(array, (value) => value++))

//打印信息
{
  operation: 'forEach',//方法名
  arrayBefore: [ 1, 2, 3, 4, 5 ],//原数组
  arrayAfter: [ 1, 2, 3, 4, 5 ],//新数组
  mutates: false,//是否改变了数组
  result: undefined//返回值
}

map

  • 作用:原数组的每个元素都调用一次 callback 函数,callback 每次执行后的返回值会组成一个新数组。

实现

js
function map(array, callback) {
  const result = []
  const length = array.length

  for (let index = 0; index < length; index++) {
    const value = array[index]
    result[index] = callback(value, index, array)
  }
  return result
}

测试

js
let arr=[1,2,3,4,5]
logOperation('map',arr,array=>map(array,value=>value+5))

{
  operation: 'map',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: [ 6, 7, 8, 9, 10 ]
}

filter

  • 作用:过滤掉回调函数返回为 false 的值,然后返回 true 的值保存到新数组中。

实现

js
function filter(array, callback) {
  const result = []
  const length = array.length

  for (let index = 0; index < length; index++) {
    const value = array[index]
    if (callback(value, index, array)) {
      result.push(value)
    }
  }

  return result
}

测试

js
let arr=[1,2,3,4,5]
logOperation('filter',arr,array=>filter(array,value=>value>2))

//打印
{
  operation: 'filter',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: [ 3, 4, 5 ]
}

reduce

  • 作用:接受个函数作为累加器,数组中的每个值开始递减,最终计算为一个值。

实现

js
function reduce(array, callback, initValue) {
  const length = array.length

  let acc = initValue
  let startAtIndex = 0
  if (initValue === undefined) {
    acc = array[0]
    startAtIndex = 0
  }

  for (let index = startAtIndex; index < length; index++) {
    const value = array[index]
    acc = callback(acc, value, index, array)
  }

  return acc
}

测试

js
let arr=[1,2,3,4,5]
logOperation('reduce',arr,array=>reduce(array,(pre,cur)=>pre+cur,0))
//打印
{
  operation: 'reduce',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: 15
}

findIndex

  • 作用:找到数组中给定值的索引

实现

js
function findIndex(array, callback) {
  const length = array.length
  for (let index = 0; index < length; index++) {
    const value = array[index]
    if (callback(value, index, array)) {
      return index
    }
  }

  return -1
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('findIndex', arr, (array) =>
  findIndex(array, (number) => number === 3)
)

//打印
{
  operation: 'findIndex',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: 2
}

find

  • 作用:返回的是实际的值,而不是索引

实现

js
function find(array, callback) {
  const length = array.length
  for (let index = 0; index < length; index++) {
    const value = array[index]
    if (callback(value, index, array)) {
      return array[index]
    }
  }
  return undefined
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('find', arr, (array) => find(array, (number) => number === 3))

//打印
{
  operation: 'find',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: 3
}

indexOf

  • 作用:获取给定索引值的另一个方法。
js
function indexOf(array, searchValue, formIndex) {
  const length = array.length

  let start = formIndex || 0

  if (start >= length || length === 0) {
    return -1
  }

  start = start >= 0 ? start : length - Math.abs(start)

  for (let index = start; index < length; index++) {
    const value = array[index]
    if (value === searchValue) {
      return index
    }
  }
  return -1
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('indexOf', arr, (array) => indexOf(array, 3))

//打印
{
  operation: 'indexOf',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: 2
}

lastIndexOf

  • 作用:返回指定元素在数组中的最后一个的索引

实现

js
function lastIndexOf(array, searchValue) {
  const length = array.length

  for (let index = length - 1; index > -1; index--) {
    const value = array[index]
    if (value === searchValue) {
      return index
    }
  }
  return -1
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('lastIndexOf', arr, (array) => lastIndexOf(array, 3))

//打印
{
  operation: 'lastIndexOf',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: 2
}

every

  • 作用:测试一个数组中的所有元素都能通过某个指定函数的测试,返回一个布尔值。

实现

js
function every(array, callback) {
  const length = array.length

  for (let index = 0; index < length; index++) {
    const value = array[index]
    if (!callback(value, index, array)) {
      return false
    }
  }
  return true
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('every', arr, (array) =>
  every(array, (number) => Number.isInteger(number))
)

//打印
{
  operation: 'every',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: true
}

some

  • 作用:some 的作用与 every 相反,只要其中一个为 true 就会返回 true。

实现

js
function some(array, callback) {
  const length = array.length

  for (let index = 0; index < length; index++) {
    const value = array[index]

    if (callback(value, index, array)) {
      return true
    }
  }
  return false
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('some', arr, (array) => some(array, (number) => number === 5))

//打印
{
  operation: 'some',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: true
}

includes

  • 作用:提供一个参数来比较数组中的元素,如果数组中含有则返回 true。

实现

js
function inclues(array, findValue) {
  const length = array.length
  for (let index = 0; index < length; index++) {
    const value = array[index]
    if (value === findValue) {
      return true
    }
  }
  return false
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('includes', arr, (array) => inclues(array, 5))


{
  operation: 'includes',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: true
}

concat

  • 作用:用于合并两个或者多个的数组,此方法不会更变原数组,而是返回一个新数组。

实现

js
function concat(array, ...values) {
  const result = [...array]
  const length = values.length

  for (let index = 0; index < length; index++) {
    const value = values[index]

    if (Array.isArray(value)) {
      result.push(...value)
    } else {
      result.push(value)
    }
  }
  return result
}

测试

js
let arr=[1,2,3,4,5]
logOperation('concat',arr,array=>concat(array,1,2,[3,4]))


{
  operation: 'concat',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: [
    1, 2, 3, 4, 5,
    1, 2, 3, 4
  ]
}

join

  • 作用:把数组中的所有元素放入一个字符串,元素是通过指定的分隔符进行分割。

实现

js
function join(array, joinWith) {
  let length = array.length

  let str = ''
  let i = 0
  if (!Array.isArray(array)) {
    return console.log('不是数组')
  }
  if (length === 0) {
    return ''
  }
  if (length === 1) {
    return `${array[0]}`
  }
  str = array[0]
  i = 1
  for (let index = i; index < length; index++) {
    const value = array[index]
    str += `${joinWith}${value}`
  }
  return str
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('join', arr, (array) => join(array, ','))

{
  operation: 'join',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: '1,2,3,4,5'
}

reverse

  • 作用:将数组中的元素的位置颠倒,并返回该数组,该方法会改变原数组。

实现

js
function reverse(array) {
  const result = []
  const lastIndex = array.length - 1
  for (let index = lastIndex; index > -1; index--) {
    const value = array[index]
    result[lastIndex - index] = value
  }
  return result
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('reverse', arr, (array) => reverse(array))

{
  operation: 'reverse',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: [ 5, 4, 3, 2, 1 ]
}

shift

  • 作用:从数组中删除第一个元素,并返回该元素的值,此方法改变数组的长度。

实现

js
function shift(array) {
  const length = array.length
  const firstValue = array[0]
  for (let index = 1; index < length; index++) {
    const value = array[index]
    array[index - 1] = value
  }
  array.length = length - 1

  return firstValue
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('shift', arr, (array) => shift(array))

{
  operation: 'shift',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 2, 3, 4, 5 ],
  mutates: true,
  result: 1
}```

## unshift

- 作用:将一个元素或多个元素添加到数组的开头,并返回该数组的新长度。

**实现**

```js
function unshift(array, ...values) {
  const mergeArr = concat(values, ...array)
  const length = mergeArr.length

  for (let index = 0; index < length; index++) {
    const value = mergeArr[index]
    array[index] = value
    array[index] = value
  }

  return array.length
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('unshift', arr, (array) => unshift(array))

{
  operation: 'unshift',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: 5
}

slice

  • 作用:返回一个截取出来的新数组。

实现

js
function slice(array, startIndex = 0, endIndex = array.length) {
  const result = []

  for (let index = startIndex; index < endIndex; index++) {
    const value = array[index]
    if (index < array.length) {
      result.push(value)
    }
  }
  return result
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('slice', arr, (array) => slice(array, 1, 3))

{
  operation: 'slice',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: [ 2, 3 ]
}

splice

  • 作用:方法通过删除或替换现有元素来修改数组。

实现

js
function splice(array, insertAtIndex, removeNumberOfElements, ...values) {
  const firstPart = slice(array, 0, insertAtIndex)
  const secondPart = slice(array, insertAtIndex + removeNumberOfElements)

  const removedElements = slice(array, insertAtIndex, insertAtIndex + removeNumberOfElements)

  const joinedParts = firstPart.concat(values, secondPart)
  const joinedPartsLength = joinedParts.length

  for (let index = 0; index < joinedPartsLength; index++) {
    array[index] = joinedParts[index]

    array.length = joinedPartsLength

    return removeNumberOfElements
  }
}

测试

js
let arr=[1,2,3,4,5]
logOperation('splice',arr,array=>splice(array,1,3))

{
  operation: 'splice',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2 ],
  mutates: true,
  result: 3
}

pop

  • 作用:从数组中删除最后一个元素,并返回该元素的值。

实现

js
function pop(array) {
  const value = array[array.length - 1]

  array.length = array.length - 1
  return value
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('pop', arr, (array) => pop(array))
{
  operation: 'pop',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4 ],
  mutates: true,
  result: 5
}

push

  • 作用:将一个或多个元素添加到数组的末尾,并返回该数组的新长度。

实现

js
function push(array, ...values) {
  const { length: arrayLength } = array
  const { length: valuesLength } = values

  for (let index = 0; index < valuesLength; index += 1) {
    array[arrayLength + index] = values[index]
  }

  return array.length
}

测试

js
let arr = [1, 2, 3, 4, 5]
logOperation('push', arr, (array) => push(array, 6, 7))

{
  operation: 'push',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [
    1, 2, 3, 4,
    5, 6, 7
  ],
  mutates: true,
  result: 7
}

fill

  • 作用:用一个占位符来填充一个数组。

实现

js
function fill(array, value, startIndex = 0, endIndex = array.length) {
  for (let index = startIndex; index < array.length; index++) {
    array[index] = value
  }
  return array
}

测试

js
let arr = new Array(5)
logOperation('fill', arr, (array) => fill(array, 1))

{
  operation: 'fill',
  arrayBefore: [ undefined, undefined, undefined, undefined, undefined ],
  arrayAfter: [ 1, 1, 1, 1, 1 ],
  mutates: true,
  result: [ 1, 1, 1, 1, 1 ]
}