返回顶部
首页 > 资讯 > 前端开发 > JavaScript >徒手实现关于JavaScript的24+数组方法
  • 272
分享到

徒手实现关于JavaScript的24+数组方法

2024-04-02 19:04:59 272人浏览 安东尼
摘要

目录一、遍历类1. forEach2. map3. every4. some5. filter6. reduce7. reduceRight二、查找类1. find2. findIn

这篇文章会和你一起探究24+原生数组方法的内部实现,相信你看完一定会有属于自己不一样的收获。

一、遍历类

1. forEach

基本使用:

forEach一个日常用的非常多的遍历函数,你一定熟悉到不能再熟悉啦!这里我们着重看一些比较重要且容易忽略的点。mdn

  • 该方法对数组的每个元素执行一次给定的函数,返回值是undefiend
  • 该方法按升序为数组中含有效值的每一项执行一次 callback 函数,未初始化的项将被跳过(例如在稀疏数组上)。
  • 如果已经存在的值被改变,则传递给 callback 的值是 forEach() 遍历到他们那一刻的值。
  • 已删除的项不会被遍历到

举个小例子:


let demoArr = [ 1, 2, 3, 4, , 5 ]

demoArr.forEach((it, i) => {
  if (i === 1) { 
    // 后添加进去的不会被访问到
    demoArr.push(5)
  } else if (i === 2) {
    // 4将不会被访问到,而4-4会被访问到
    demoArr.splice(3, 1, '4-4')
  }

  console.log(it)
})


代码实现:


Array.prototype.forEach2 = function (callback, thisCtx) {
  if (typeof callback !== 'function') {
    throw `${callback} is not a function`
  }

  const length = this.length
  let i = 0

  while (i < length) {
    // 被删除的,新增的元素索引i不在数组内,所以不会被访问到
    if (i in this) {
      callback.call(thisCtx, this[ i ], i, this)
    }

    i++
  }
}

同样用刚才的例子,改下后的输出是一样的

测试一把:


// 测试
let demoArr = [ 1, 2, 3, 4, , 5 ]

demoArr.forEach2((it, i) => {
  if (i === 1) {
    // 后添加进去的不会被访问到
    demoArr.push(5)
  } else if (i === 2) {
    // 4将不会被访问到,相仿4-4会被访问到
    demoArr.splice(3, 1, '4-4')
  }

  console.log(it)
})


2. map

基本使用:

map 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。mdn

注意点:

  • callback 函数只会在有值的索引上被调用
  • 从来没被赋过值或者使用 delete 删除的索引则不会被调用。

// 注意索引为2的位置没有赋值
let arr = [ 1, 2, ,4, 5 ]

// 删除索引3
delete arr[3]

console.log(arr.map((it) => it * it))
// [ 1, 4, 25 ]

代码实现:

点击查看源码实现


Array.prototype.map2 = function (callback, thisCtx) {
  if (typeof callback !== 'function') {
    throw `${callback} is not a function`
  }

  const length = this.length
  let i = 0
  // map返回值是一个新的数组
  let newArray = []

  while (i < length) {
    // 被删除的,未初始化的都不会被遍历到
    if (i in this) {
      newArray.push(callback.call(thisCtx, this[ i ], i, this))
    }

    i++
  }
  // 返回新的数组
  return newArray
}



测试一把:


let arr = [ 0, 1, 2, 3, 4,, 5 ]

let arr2 = arr.map2(function (it, i, array) {
  console.log(it, i, array, this)
  return it * it
}, { name: '前端胖头鱼' })

console.log(arr2)

3. every

基本使用:

every 方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。mdn

注意点:

  • 若收到一个空数组,此方法在一切情况下都会返回 true。
  • callback 只会为那些已经被赋值的索引调用
  • 不会为那些被删除或从未被赋值的索引调用

// 举例
let emptyArr = []
// 空数组直接返回true
console.log(emptyArr.every((it) => it > 0)) // true
// 有未被赋值的
let arr = [ 0, 1, 2, 3, 4,, 5, -1 ]
// 删除元素
delete arr[7]

console.log(arr.every((it) => it >= 0)) // true

代码实现:

点击查看源码实现


Array.prototype.every2 = function (callback, thisCtx) {
  if (typeof callback !== 'function') {
    throw `${callback} is not a function`
  }

  const length = this.length
  let i = 0
  // 空函数不会走进循环
  while (i < length) {
    // 只要有一个值不符合callback预期就返回false
    if (i in this && !callback.call(thisCtx, this[ i ], i, this)) {
      return false
    }

    i++
  }

  return true
}

测试一把:

还是拿例子做测试


let emptyArr = []

console.log(emptyArr.every2((it) => it > 0)) // true

let arr = [ 0, 1, 2, 3, 4,, 5, -1 ]

delete arr[7]

console.log(arr.every2((it) => it >= 0)) // true



4. some

基本使用:

some 方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。 mdn

注意点:

  • callback 只会在那些”有值“的索引上被调用,不会在那些被删除或从来未被赋值的索引上调用。

举个例子


let emptyArr = []
// 空数组直接返回false
console.log(emptyArr.some((it) => it > 0)) // false
let arr = [ 0, 1, 2, 3, 4,, 5, -1 ]
// 还没有遍历前把-1删除了,唯一小于0的值不存在了,即返回false
delete arr[7]

console.log(arr.some((it) => it < 0)) // false

代码实现:

点击查看源码实现


Array.prototype.some2 = function (callback, thisCtx) {
  if (typeof callback !== 'function') {
    throw `${callback} is not a function`
  }

  const length = this.length
  let i = 0

  while (i < length) {
    // 只要有一个元素符合callback条件,就返回true
    if (i in this && callback.call(thisCtx, this[ i ], i, this)) {
      return true
    }

    i++
  }

  return false
}

测试一把:


let emptyArr = []
// 空数组直接返回true
console.log(emptyArr.some2((it) => it > 0)) // false
let arr = [ 0, 1, 2, 3, 4,, 5, -1 ]

delete arr[7]

console.log(arr.some2((it) => it < 0)) // false
console.log(arr.some2((it) => it > 0)) // true

5. filter

基本使用:

filter 方法创建一个新数组, 其包含通过所提供函数测试的所有元素。 mdn

注意点:

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

// 索引为5的位置,没有初始化值,不会被遍历
let arr = [ 0, 1, 2, -3, 4,, 5 ]
// 删除掉最后一个元素
delete arr[6]
// 过滤出大于0的值
let filterArr = arr.filter((it) => it > 0)

console.log(filterArr) // [ 1, 2, 4 ]

代码实现:

点击查看源码实现


Array.prototype.filter2 = function (callback, thisCtx) {
  if (typeof callback !== 'function') {
    throw `${callback} is not a function`
  }

  const length = this.length
  let newArray = []
  let i = 0

  while (i < length) {
    if (i in this && callback.call(thisCtx, this[ i ], i, this)) {
      newArray.push(this[ i ])
    }
    i++
  }

  return newArray
}

测试:


// 索引为5的位置,没有初始化值,不会被遍历
let arr = [ 0, 1, 2, -3, 4,, 5 ]
// 删除掉最后一个元素
delete arr[6]
// 过滤出大于0的值
let filterArr = arr.filter2((it) => it > 0)

console.log(filterArr) // [ 1, 2, 4 ]

6. reduce

基本使用:

reduce 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值 mdn

这个函数稍微复杂一些,我们用一个例子来看一下他是怎么用的。


const sum = [1, 2, 3, 4].reduce((prev, cur) => {
  return prev + cur;
})

console.log(sum) // 10

// 初始设置
prev = initialValue = 1, cur = 2

// 第一次迭代
prev = (1 + 2) =  3, cur = 3

// 第二次迭代
prev = (3 + 3) =  6, cur = 4

// 第三次迭代
prev = (6 + 4) =  10, cur = undefined (退出)

代码实现:

点击查看源码实现


Array.prototype.reduce2 = function (callback, initValue) {
  if (typeof callback !== 'function') {
    throw `${callback} is not a function`
  }

  let pre = initValue
  let i = 0
  const length = this.length
  // 当没有传递初始值时,取第一个作为初始值  
  if (typeof pre === 'undefined') {
    pre = this[0]
    i = 1
  }

  while (i < length) {
    if (i in this) {
      pre = callback(pre, this[ i ], i, this)
    }
    i++
  }

  return pre
}

测试:


const sum = [1, 2, 3, 4].reduce2((prev, cur) => {
  return prev + cur;
})

console.log(sum) // 10

7. reduceRight

基本使用:

reduceRight 方法对数组中的每个元素执行一个由您提供的reducer函数(降序执行),将其结果汇总为单个返回值 mdn

reduce很类似,唯一不同的是reduceRight从右往左遍历


const sum = [1, 2, 3, 4].reduce((prev, cur) => {
  console.log(cur)
  return prev + cur;
})

// 2 1
// 3 2
// 4 3

console.log(sum) // 10

const sum2 = [1, 2, 3, 4].reduceRight((prev, cur) => {
  console.log(cur)
  return prev + cur;
})
// 3 2 
// 2 1
// 1 0

console.log(sum2) // 10

代码实现:

点击查看源码实现


Array.prototype.reduceRight2 = function (callback, initValue) {
  if (typeof callback !== 'function') {
    throw `${callback} is not a function`
  }

  let pre = initValue
  const length = this.length
  // 从最后一个元素开始遍历
  let i = length - 1
  // 如果没有传递初始值,则取最后一个作为初始值
  if (typeof pre === 'undefined') {
    pre = this[i]
    i--
  }

  while (i >= 0) {
    if (i in this) {
      pre = callback(pre, this[ i ], i, this)
    }
    i--
  }

  return pre
}

测试:


const sum = [1, 2, 3, 4].reduceRight2((prev, cur) => {
  console.log(cur)
  return prev + cur;
})

// 3 2
// 2 1
// 1 0

console.log(sum) // 10

二、查找类

1. find

基本使用:

find 方法返回数组中满足测试函数的第一个元素的值。否则返回 undefined, mdn

注意点:

  • find方法对数组中的每一项元素执行一次 callback 函数,直至有一个 callback 返回 true
  • 当找到了这样一个元素后,该方法会立即返回这个元素的值,否则返回 undefined
  • callback 函数会为数组中的每个索引调用即从 0 到 length - 1,而不仅仅是那些被赋值的索引。(这个点是和前面几个函数不一样的地方)

let arr = [ 0, 1, 2, 3, 4,, 5 ]

let index = arr.find((it) =>  {
  return it > 3
}, { name: '前端胖头鱼' })

console.log(index) // 4

代码实现:


Array.prototype.find2 = function (callback, thisCtx) {
  if (typeof callback !== 'function') {
    throw `${callback} is not a function`
  }

  const length = this.length
  let i = 0

  while (i < length) {
    const value = this[ i ]
    // 只要有一个元素符合callback回调函数的逻辑,就返回元素value
    if (callback.call(thisCtx, value, i, this)) {
      return value
    }

    i++
  }
  // 否则返回undefined  
  return undefined
}

测试:


let arr = [ 0, 1, 2, 3, 4,, 5 ]

let index = arr.find2(function (it, i, array) {
  console.log(it, i, array, this)
  return it > 3
}, { name: '前端胖头鱼' })

console.log(index) // 4

2. findIndex

基本使用:

  • findIndex方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。 mdn
  • 和find函数不同的地方在于,findIndex是返回索引而非值, 注意点也和find基本一样
  • findIndex方法对数组中的每个数组索引0 ~ length-1(包括)执行一次callback函数,直到找到一个callback函数返回true的值。
  • 如果找到这样的元素,findIndex会立即返回该元素的索引。如果回调从不返回真值,或者数组的length为0,则findIndex返回-1
  • 与某些其他数组方法(如Array#some)不同,在稀疏数组中,即使对于数组中不存在的条目的索引也会调用回调函数

let arr = [ 0, 1, 2, 3, 4,, 5 ]

let index = arr.findIndex((it, i, array) => {
  return it > 2
})

console.log(index) // 3

代码实现:

点击查看源码实现


Array.prototype.findIndex2 = function (callback, thisCtx) {
  if (typeof callback !== 'function') {
    throw `${callback} is not a function`
  }

  const length = this.length
  let i = 0

  while (i < length) {
    // 符合callback逻辑的直接返回索引i
    if (callback.call(thisCtx, this[ i ], i, this)) {
      return i
    }

    i++
  }
  // 否则返回-1  
  return -1
}

测试:


let arr = [ 0, 1, 2, 3, 4,, 5 ]

let index = arr.findIndex2(function (it, i, array) {
  console.log(it, i, array, this)
  return it > 2
}, { name: '前端胖头鱼' })

console.log(index) // 3

3. indexOf

基本使用:

indexOf方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。 mdn

arr.indexOf(searchElement[, fromIndex])

注意点:

  • 如果开始查找的索引值大于或等于数组长度,意味着不会在数组里查找,返回-1
  • 如果参数中提供的索引值是一个负值,则将其作为数组末尾的一个抵消,即-1表示从最后一个元素开始查找,-2表示从倒数第二个元素开始查找 ,以此类推
  • 如果参数中提供的索引值是一个负值,并不改变其查找顺序,查找顺序仍然是从前向后查询数组
  • 如果抵消后的索引值仍小于0,则整个数组都将会被查询。其默认值为0.

const array = [2, 5, 9]

console.log(array.indexOf(2))      // 0
console.log(array.indexOf(7))      // -1
console.log(array.indexOf(9, 2))   // 2
console.log(array.indexOf(2, -1))  // -1
console.log(array.indexOf(2, -3))  // 0

代码实现

点击查看源码实现

有了上面的注意点和基本你使用,聪明的你肯定一眼就知道怎么写啦


Array.prototype.indexOf2 = function (targetEle, fromIndex) {
  const length = this.length

  fromIndex = +fromIndex || 0

  // 数组为空或者从大于等于数组长度的地方开始检索,都直接是-1
  if (length === 0 || fromIndex >= length) {
    return -1
  }
  
  let i = Math.max(fromIndex >= 0 ? fromIndex : length - Math.abs(fromIndex), 0)

  while (i < length) {
    // 在数组内的元素并且和targetEle强等
    if (i in this && targetEle === this[ i ]) {
      return i
    }

    i++
  }

  return -1
}

测试:


const array = [2, 5, 9]

console.log(array.indexOf2(2))      // 0
console.log(array.indexOf2(7))      // -1
console.log(array.indexOf2(9, 2))   // 2
console.log(array.indexOf2(2, -1))  // -1
console.log(array.indexOf2(2, -3))  // 0

4. lastIndexOf

基本使用:

lastIndexOf 方法返回指定元素在数组中的最后一个的索引,如果不存在则返回 -1。 mdn

arr.lastIndexOf(searchElement[, fromIndex])

注意点:

  • arr.length - 1位置开始逆向查找。
  • 如果fromIndex大于或等于数组的长度,则整个数组会被查找。
  • 如果fromIndex为负值,将其视为从数组末尾向前的偏移。即使该值为负,数组仍然会被从后向前查找。
  • 如果fromIndex值为负时,其绝对值大于数组长度,则方法返回 -1,即数组不会被查找。

let array = [2, 5, 9, 2]

console.log(array.lastIndexOf(2)) // 3
console.log(array.lastIndexOf(7)) // -1
console.log(array.lastIndexOf(2, 3)) // 3
console.log(array.lastIndexOf(2, 2)) // 0
console.log(array.lastIndexOf(2, -2)) // 0
console.log(array.lastIndexOf(2, -1)) // 3

代码实现:

点击查看源码实现


Array.prototype.lastIndexOf2 = function (targetEle, fromIndex) {
  const length = this.length

  fromIndex = typeof fromIndex === 'undefined' ? length - 1 : fromIndex
  // 数组为空,以及该值为负时且绝对值大于数组长度,则方法返回 -1,即数组不会被查找。
  if (length === 0 || fromIndex < 0 && Math.abs(fromIndex) >= length) {
    return -1
  }

  let i

  if (fromIndex >= 0) {
    // 如果`fromIndex`大于或等于数组的长度,则整个数组会被查找。
    // 也就是当大于数组length - 1时,会取length - 1
    i = Math.min(fromIndex, length - 1)
  } else {
    i = length - Math.abs(fromIndex)
  }

  while (i >= 0) {
    // 等于targetEle时返回索引
    if (i in this && targetEle === this[ i ]) {
      return i
    }
    // 逆向遍历
    i--
  }
  // 没找到返回-1
  return -1
}

测试:


let array = [2, 5, 9, 2]

console.log(array.lastIndexOf2(2)) // 3
console.log(array.lastIndexOf2(7)) // -1
console.log(array.lastIndexOf2(2, 3)) // 3
console.log(array.lastIndexOf2(2, 2)) // 0
console.log(array.lastIndexOf2(2, -2)) // 0
console.log(array.lastIndexOf2(2, -1)) // 3

5. includes

基本使用:

includes 方法用来判断一个数组是否包含一个指定的值,如果包含则返回 true,否则返回false。mdn

arr.includes(valueToFind[, fromIndex])

注意点:

  • 从fromIndex 索引处开始查找 valueToFind
  • 如果为负值,则按升序从 array.length + fromIndex 的索引开始搜
  • 数组中存在NaN的话,[ ..., NaN ].includes(NaN)为true

console.log([1, 2, 3].includes(2))     // true
console.log([1, 2, 3].includes(4))     // false
console.log([1, 2, 3].includes(3, 3))  // false
console.log([1, 2, 3].includes(3, -1)) // true
console.log([1, 2, NaN].includes(NaN)) // true

代码实现:

点击查看源码实现


Array.prototype.includes2 = function (targetEle, fromIndex) {
  const length = this.length

  fromIndex = +fromIndex || 0

  // 数组为空或者从大于等于数组长度的地方开始检索,都直接是-1
  if (length === 0 || fromIndex >= length) {
    return false
  }
  
  let i = Math.max(fromIndex >= 0 ? fromIndex : length - Math.abs(fromIndex), 0)

  while (i < length) {
    const value = this[ i ]
    // 注意NaN情况
    if (targetEle === value || typeof targetEle === 'number' && typeof value === 'number' && isNaN(targetEle) && isNaN(value)) {
      return true
    }

    i++
  }

  return false
}

测试:

console.log([1, 2, 3].includes2(2))     // true
console.log([1, 2, 3].includes2(4))     // false
console.log([1, 2, 3].includes2(3, 3))  // false
console.log([1, 2, 3].includes2(3, -1)) // true
console.log([1, 2, NaN].includes2(NaN)) // true

三、增删改类

1. push

基本使用:

push 方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。mdn


const animals = ['pigs', 'Goats', 'sheep']
animals.push('cows')

console.log(animals, animals.length) 
// ["pigs", "goats", "sheep", "cows"], 4

animals.push('chickens', 'cats', 'dogs')

console.log(animals, animals.length) 

// ["pigs", "goats", "sheep", "cows", "chickens", "cats", "dogs"], 7

代码实现

点击查看源码实现


Array.prototype.push2 = function (...pushEles) {
  const pushEleLength = pushEles.length
  const length = this.length

  let i = 0
  
  while (i < pushEleLength) {
    this[ length + i ] = pushEles[ i ]
    i++
  }

  return this.length
}

测试:


const animals = ['pigs', 'goats', 'sheep']
animals.push2('cows')

console.log(animals, animals.length) 
// ["pigs", "goats", "sheep", "cows"], 4

animals.push2('chickens', 'cats', 'dogs')

console.log(animals, animals.length) 

// ["pigs", "goats", "sheep", "cows", "chickens", "cats", "dogs"], 7

2. pop

基本使用:

pop方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。mdn


let arr = [ 1, 2 ]
let arr2 = []

console.log(arr.pop(), arr) // 2 [1]
console.log(arr2.pop(), arr2) // undefined []

代码实现和使用一样简单,只要把数组的最后一个元素返回,并且让数组长度减1即可

代码实现:

点击查看源码实现


Array.prototype.pop2 = function () {
  const length = this.length
  // 空数组上pop,直接返回undefined
  if (length === 0) {
    return undefined
  }

  const delEle = this[ length - 1 ]

  this.length = length - 1

  return delEle
}

测试:


let arr = [ 1, 2 ]
let arr2 = []

console.log(arr.pop2(), arr) // 2 [1]
console.log(arr2.pop2(), arr2) // undefined []

3. unshift

基本使用:

unshift  方法将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组 ) 。

注意点:

  • 如果传入多个参数,它们会被以块的形式插入到对象的开始位置,它们的顺序和被作为参数传入时的顺序一致。
  • 传入多个参数调用一次 unshift ,和传入一个参数调用多次 unshift (例如,循环调用),它们将得到不同的结果。

例如:


let arr = [4,5,6]
// 一次性插入
arr.unshift(1,2,3)

console.log(arr) // [1, 2, 3, 4, 5, 6]

let arr2 = [4,5,6]
// 插入多次
arr2.unshift(1)
arr2.unshift(2)
arr2.unshift(3)

console.log(arr2); // [3, 2, 1, 4, 5, 6]

代码实现:

点击查看源码实现


Array.prototype.unshift2 = function (...unshiftEles) {
  // 借助扩展符,将需要添加的元素以块的形式插入到数组前面
  let newArray = [ ...unshiftEles, ...this ]
  let length = newArray.length
  
  let i = 0

  if (unshiftEles.length === 0) {
    return length
  }
  // 重新复制给数组
  while (i < length) {
    this[ i ] = newArray[ i ]
    i++
  }
  
  return this.length
}

测试:


let arr = [4,5,6]
// 一次性插入
arr.unshift2(1,2,3)

console.log(arr) // [1, 2, 3, 4, 5, 6]

let arr2 = [4,5,6]
// 插入多次
arr2.unshift2(1)
arr2.unshift2(2)
arr2.unshift2(3)

console.log(arr2); // [3, 2, 1, 4, 5, 6]

4. shift

基本使用:

shift 方法从数组中删除第一个元素,并返回该元素的值。 mdn


let arr = [ 1, 2 ]

console.log(arr.shift(), arr) // 1 [2]
console.log(arr.shift(), arr) // 2 []

代码实现:

点击查看源码实现


Array.prototype.shift2 = function () {
  const length = this.length
  const delValue = this[ 0 ]

  let i = 1

  while (i < length) {
    // 从第一个元素开始,后面的元素都往前移动一位
    this[ i - 1 ] = this[ i ]
    i++
  }
  // 设置好数组的长度
  this.length = length - 1
  // 返回删除的值
  return delValue
}

测试:


let arr = [ 1, 2 ]

console.log(arr.shift2(), arr) // 1 [2]
console.log(arr.shift2(), arr) // 2 []

5. reverse

基本使用:

reverse 方法将数组中元素的位置颠倒,并返回该数组。即数组的第一个元素会变成最后一个,数组的最后一个元素变成第一个。mdn


``` javascript
const arr = [1, 2, 3]

console.log(arr) // [1, 2, 3]

arr.reverse()

console.log(arr) // [3, 2, 1]

代码实现:

点击查看源码实现


Array.prototype.reverse2 = function () {
  // 设置双指针,往中间靠拢
  let i = 0
  let j = this.length - 1

  while (i < j) {
    // 第一个和最后一个,第二个和倒数第二个进行位置调换
    [ this[ i ], this[ j ] ] = [ this[ j ], this[ i ] ]
    i++
    j--
  }

  return this
}

测试:


const arr = [1, 2, 3]

console.log(arr) // [1, 2, 3]

arr.reverse2()

console.log(arr) // [3, 2, 1]

6. fill

基本使用:

fill 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。mdn


const array1 = [1, 2, 3, 4];

console.log(array1.fill(0, 2, 4)) // [1, 2, 0, 0]


console.log(array1.fill(5, 1)) // [1, 5, 5, 5]

console.log(array1.fill(6)) // [6, 6, 6, 6]

代码实现:

点击查看源码实现


Array.prototype.fill2 = function (value, start, end) {
  const length = this.length

  start = start >> 0
  // end没填的话,默认是length,否则取填写的 
  end = typeof end === 'undefined' ? length : end >> 0
  // start最小取0,最大取length
  start = start >= 0 ? Math.min(start, length) : Math.max(start + length, 0)
  // end最小取0,最大取length 
  end = end >= 0 ? Math.min(end, length) : Math.max(end + length, 0)
  // 填充指定范围的索引为value
  while (start < end) {
    this[ start ] = value
    start++
  }
  // 返回被修改的数组
  return this
}

测试:


const array1 = [1, 2, 3, 4];

console.log(array1.fill2(0, 2, 4)) // [1, 2, 0, 0]


console.log(array1.fill2(5, 1)) // [1, 5, 5, 5]

console.log(array1.fill2(6)) // [6, 6, 6, 6]


连接、拼接

7. concat

基本使用:

concat 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组 mdn


 let num1 = [[1]]
let num2 = [2, [3]]
let num3=[5,[6]]

let nums = num1.concat(num2) // [[1], 2, [3]]
let nums2 = num1.concat(4, num3) // [[1], 4, 5,[6]]

代码实现:

点击查看源码实现


Array.prototype.concat2 = function (...concatEles) {
  const length = concatEles.length
  // 数组本身展开一层
  let newArray = [ ...this ]
  let i = 0

  while (i < length) {
    const value = concatEles[ i ]
    // 对数组元素展开一层 
    Array.isArray(value) ? newArray.push(...value) : newArray.push(value)
    i++
  }

  return newArray
}

测试:


let num1 = [[1]]
let num2 = [2, [3]]
let num3=[5,[6]]

let nums = num1.concat2(num2) // [[1], 2, [3]]
let nums2 = num1.concat2(4, num3) // [[1], 4, 5,[6]]

8. join

基本使用:

join 方法将一个数组的所有元素通过字符标识连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。


const elements = ['Fire', 'air', 'Water']
const elements2 = ['Fire']

console.log(elements.join()) // Fire,Air,Water
console.log(elements.join('')) // FireAirWater
console.log(elements.join('-')) //  Fire-Air-Water
console.log(elements2.join('-')) // Fire

代码实现:

点击查看源码实现


Array.prototype.join2 = function (fORMat = ',') {
  const length = this.length
  // 保存最后一个元素,因为他不参与format连接 
  let lastEle = this[ length - 1 ]
  let string = ''

  if (length === 0) {
    return string
  }

  for (i = 0; i < length - 1; i++) {
    string += this[ i ] + format
  }

  return string + lastEle
}

 测试:


const elements = ['Fire', 'Air', 'Water']
const elements2 = ['Fire']

console.log(elements.join2()) // Fire,Air,Water
console.log(elements.join2('')) // FireAirWater
console.log(elements.join2('-')) //  Fire-Air-Water
console.log(elements2.join2('-')) // Fire

四、静态方法

1. Array.isArray

基本使用:

Array.isArray() 用于确定传递的值是否是一个 Array。


Array.isArray([1, 2, 3]) // true

Array.isArray({foo: 123}) // false

Array.isArray("foobar") // false

Array.isArray(undefined) // false

代码实现:

点击查看源码实现

这个非常简单,只需要一句话就可以


Array.isArray2 = function (ele) {
  return  Object.prototype.toString.call(ele) === '[object Array]';
}

测试:


Array.isArray2([1, 2, 3]) // true

Array.isArray2({foo: 123}) // false

Array.isArray2("foobar") // false

Array.isArray2(undefined) // false

2. Array.of

基本使用:

Array.of 方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。

注意点:

  • Array.of()  和 Array 构造函数之间的区别在于处理整数参数:
  • Array.of(7) 创建一个具有单个元素 7 的数组,而 Array(7) 创建一个长度为7的空数组(注意: 这是指一个有7个空位(empty)的数组,而不是由7个undefined组成的数组)

Array.of(7);       // [7]
Array.of(1, 2, 3); // [1, 2, 3]

Array(7);          // [ , , , , , , ]
Array(1, 2, 3);    // [1, 2, 3]

代码实现:

击查看源码实现

实现思路就是把你穿进去的值,挨个赋值到当前数组即可


Array.of2 = function (...eles) {
  const length = eles.length
  let i = 0
  let newArray = []

  while (i < length) {
    newArray[ i ] = eles[ i ]
    i++
  }

  return newArray
}

测试:


Array.of2(7);       // [7]
Array.of2(1, 2, 3); // [1, 2, 3]

五、扁平类

1. flat

基本使用:

flat()  方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。 mdn


const arr1 = [0, 1, 2, [3, 4]];

console.log(arr1.flat()) // [0, 1, 2, 3, 4] 默认会平铺展开一层


const arr2 = [0, 1, 2, [[[3, 4]]]]

console.log(arr2.flat(2)) // [0, 1, 2, [3, 4]] 指定展开两层

代码实现:

点击查看源码实现


Array.prototype.flat2 = function (depth = 1) {
  const result = []
  const flat = (arr, depth) => {
    for (let item of arr) {
      // 当层数还未全部展开的时候,进行递归处理
      if (Array.isArray(item) && depth > 0) {
        flat(item, depth - 1)
      } else {
        // 去除空元素,添加非undefined元素
        item !== void 0 && result.push(item)
      }
    }
  }

  flat(this, depth)

  return result
}

测试:


const arr1 = [0, 1, 2, [3, 4]];

console.log(arr1.flat2()) // [0, 1, 2, 3, 4]


const arr2 = [0, 1, 2, [[[3, 4]]]]

console.log(arr2.flat2(2)) // [0, 1, 2, [3, 4]] 

2. flatMap

基本使用:

flatMap 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 连着深度值为1的 flat 几乎相同。 mdn


let arr = [1, 2, 3, 4]


arr.flatMap(x => [x * 2]) // [2, 4, 6, 8]

代码实现:

点击查看源码实现


Array.prototype.flatMap2 = function (callback, thisCtx) {
  if (typeof callback !== 'function') {
    throw `${callback} is not a function`
  }
  // map和flat具体实现可以看map.js和flat.js
  return this.map(function (it, i, array) {
    return callback.call(thisCtx, it, i, array)
  }).flat(1)
}

测试:


let arr = [1, 2, 3, 4]


arr.flatMap2(x => [x * 2]) // [2, 4, 6, 8]

结尾:

到此这篇关于徒手实现关于JavaScript的24+数组方法的文章就介绍到这了,更多相关实现关于JavaScript的24+数组方法内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

国庆将至,祝大家节日快乐,浪浪浪七天乐。

--结束END--

本文标题: 徒手实现关于JavaScript的24+数组方法

本文链接: https://lsjlt.com/news/137032.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 徒手实现关于JavaScript的24+数组方法
    目录一、遍历类1. forEach2. map3. every4. some5. filter6. reduce7. reduceRight二、查找类1. find2. findIn...
    99+
    2024-04-02
  • 关于JavaScript的Array数组方法详解
    目录数组的方法1. push() 添加2. pop() 删除4. shift() 删除7. splice() 删除8. concat() 连接9. join()10. re...
    99+
    2023-05-20
    JavaScript 数组 JavaScript Array
  • 关于JavaScript中的数组方法和循环
    目录1、基本概念2、创建数组的三种方法3、访问数组4、数组常用属性5、数组常用方法6、常用的循环遍历数组的方法1、基本概念 JavaScript 数组用于在单一变量中存储多个值。是一...
    99+
    2024-04-02
  • 关于JavaScript数组对象去重的几种方法
    数组对象如下: let repeatData = [ { id: 1, name: 'sun', age: 18 }, { id: 1, name: ...
    99+
    2023-05-17
    JavaScript数组去重 js数组对象去重
  • JavaScript中关于数组的调用方式
    目录JavaScript数组的调用伪数组JS调用数组方法总结JavaScript数组的调用 1.数组的调用 描述:数组的调用实际上是指数组元素的调用。数组元素通过【数组名+下标】的方...
    99+
    2023-02-10
    JavaScript数组 数组的调用 JS数组调用
  • 徒手打造基于Spark的数据工厂(Data Factory):从设计到实现
    在大数据处理和人工智能时代,数据工厂(Data Factory)无疑是一个非常重要的大数据处理平台。市面上也有成熟的相关产品,比如Azure Data Factory,不仅功能强大,而且依托微软的云计算平台Azure,为大数据处理提供了强...
    99+
    2018-01-13
    徒手打造基于Spark的数据工厂(Data Factory):从设计到实现
  • javascript实现json转数组的方法
    这篇文章给大家分享的是有关javascript实现json转数组的方法的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。javascript实现json转数组的方法是通过jsonStr实现,代码为【var jsonS...
    99+
    2023-06-14
  • JavaScript实现数组去重的7种方法
    目录前言方法实现双循环去重indexOf方法去重1indexOf方法去重2相邻元素去重利用对象属性去重set与解构赋值去重Array.from与set去重总结前言 去重是开发中经常会...
    99+
    2024-04-02
  • JavaScript 手动实现instanceof的方法
    1. instanceof的用法 instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。 function Person() {} ...
    99+
    2024-04-02
  • JavaScript中数组flat方法的使用与实现方法
    目录前言语法参数返回值使用示例方法实现1、当只扁平化一层的时候2、当数组展平的层数为最大层时3、数组扁平化使用参数控制扁平的深度总结前言 flat() 方法会按照一个可指定的深度递归...
    99+
    2024-04-02
  • 关于PHP数组迭代器的使用方法实例
    近来在开发一个视力筛查电子报告系统的产品,这个产品的作用是自动提取视力筛查过程中得到的屈光检查数据,并结合数据自动生成通俗易懂且专业的电子报告,以方便家长可以通过公众号或H5链接查阅。 要实现这个需求,第一步是对验光设备里打印出来的纸质报告...
    99+
    2015-05-29
    php数组迭代器 如何实现迭代器 数组迭代方法
  • 关于JavaScript轮播图的实现
    今天又是一个非常实用的案例哟,听名字就觉得高级很难对吧,今天就来写一个案例,让你轻松学到轮播图的精髓!!  还是老规矩,来看一下实现效果!! 学习轮播图的首先是要把图片准...
    99+
    2024-04-02
  • 关于JavaScript的URL.createObjectURL()的使用方法
    URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 docume...
    99+
    2023-05-17
    JavaScript createObjectURL() URL.createObjectURL()
  • Javascript继承关系的实现方法
    本篇内容介绍了“Javascript继承关系的实现方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!说明JavaScript中的继承关系是通...
    99+
    2023-06-20
  • 关于ES6中数组新增的方法详解
    目录在ES6之前,创建数组的方式有2种:Array.find((item,indexArr,arr)=>{}) 掌握Array.findIndex((item, index, ...
    99+
    2024-04-02
  • 关于找到任意组件实例的方法
    目录找到任意组件实例的方法vue常用组件库移动端常用组件库pc端常用组件库找到任意组件实例的方法 由一个组件,向上找到最近的指定组件 function findComponentU...
    99+
    2024-04-02
  • JavaScript数组中迭代方法怎么实现
    今天小编给大家分享一下JavaScript数组中迭代方法怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我...
    99+
    2024-04-02
  • JavaScript中ES5如何实现数组map方法
    这篇文章将为大家详细讲解有关JavaScript中ES5如何实现数组map方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。ES5 实现数组 map 方法值得一提的是,map 的第二个参数为第一个参数回调...
    99+
    2023-06-27
  • JavaScript数组实例的9个方法
    目录前言mapfiltersomeeveryreduceforEachfind和findIndexjoin总结前言 手写JS原生API在面试中很常见,今天努力工作之余(摸鱼的时候)翻...
    99+
    2024-04-02
  • JavaScript如何使用reduce实现数组的flat方法
    这篇文章主要介绍了JavaScript如何使用reduce实现数组的flat方法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作