欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

徒手實(shí)現(xiàn)關(guān)于JavaScript的24+數(shù)組方法

 更新時(shí)間:2021年09月28日 14:58:04   作者:前端胖頭魚  
數(shù)組是我們?nèi)粘9ぷ髦杏玫淖铑l繁的一類數(shù)據(jù)結(jié)構(gòu),能幫助我們解決許多問題,而其本身也包含接近33個(gè)之多的方法,做了一個(gè)腦圖分類如下,熟練使用數(shù)組的你,是否想知道他們內(nèi)部的實(shí)現(xiàn)原理呢?接下來小編就帶大家進(jìn)入主題,希望能幫助到你

這篇文章會(huì)和你一起探究24+原生數(shù)組方法的內(nèi)部實(shí)現(xiàn),相信你看完一定會(huì)有屬于自己不一樣的收獲。

一、遍歷類

1. forEach

基本使用:

forEach一個(gè)日常用的非常多的遍歷函數(shù),你一定熟悉到不能再熟悉啦!這里我們著重看一些比較重要且容易忽略的點(diǎn)。mdn

  • 該方法對(duì)數(shù)組的每個(gè)元素執(zhí)行一次給定的函數(shù),返回值是undefiend
  • 該方法按升序?yàn)閿?shù)組中含有效值的每一項(xiàng)執(zhí)行一次 callback 函數(shù),未初始化的項(xiàng)將被跳過(例如在稀疏數(shù)組上)。
  • 如果已經(jīng)存在的值被改變,則傳遞給 callback 的值是 forEach() 遍歷到他們那一刻的值。
  • 已刪除的項(xiàng)不會(huì)被遍歷到

舉個(gè)小例子:

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

demoArr.forEach((it, i) => {
  if (i === 1) { 
    // 后添加進(jìn)去的不會(huì)被訪問到
    demoArr.push(5)
  } else if (i === 2) {
    // 4將不會(huì)被訪問到,而4-4會(huì)被訪問到
    demoArr.splice(3, 1, '4-4')
  }

  console.log(it)
})

/*
 1
 2
 3
 4-4
 5
*/

代碼實(shí)現(xiàn):

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不在數(shù)組內(nèi),所以不會(huì)被訪問到
    if (i in this) {
      callback.call(thisCtx, this[ i ], i, this)
    }

    i++
  }
}

同樣用剛才的例子,改下后的輸出是一樣的

測(cè)試一把:

// 測(cè)試
let demoArr = [ 1, 2, 3, 4, , 5 ]

demoArr.forEach2((it, i) => {
  if (i === 1) {
    // 后添加進(jìn)去的不會(huì)被訪問到
    demoArr.push(5)
  } else if (i === 2) {
    // 4將不會(huì)被訪問到,相仿4-4會(huì)被訪問到
    demoArr.splice(3, 1, '4-4')
  }

  console.log(it)
})

/*
 1
 2
 3
 4-4
 5
*/

2. map

基本使用:

map 方法創(chuàng)建一個(gè)新數(shù)組,其結(jié)果是該數(shù)組中的每個(gè)元素是調(diào)用一次提供的函數(shù)后的返回值。mdn

注意點(diǎn):

  • callback 函數(shù)只會(huì)在有值的索引上被調(diào)用
  • 從來沒被賦過值或者使用 delete 刪除的索引則不會(huì)被調(diào)用。
// 注意索引為2的位置沒有賦值
let arr = [ 1, 2, ,4, 5 ]

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

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

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

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

  const length = this.length
  let i = 0
  // map返回值是一個(gè)新的數(shù)組
  let newArray = []

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

    i++
  }
  // 返回新的數(shù)組
  return newArray
}



測(cè)試一把:

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 方法測(cè)試一個(gè)數(shù)組內(nèi)的所有元素是否都能通過某個(gè)指定函數(shù)的測(cè)試。它返回一個(gè)布爾值。mdn

注意點(diǎn):

  • 若收到一個(gè)空數(shù)組,此方法在一切情況下都會(huì)返回 true。
  • callback 只會(huì)為那些已經(jīng)被賦值的索引調(diào)用
  • 不會(huì)為那些被刪除或從未被賦值的索引調(diào)用
// 舉例
let emptyArr = []
// 空數(shù)組直接返回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

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

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

  const length = this.length
  let i = 0
  // 空函數(shù)不會(huì)走進(jìn)循環(huán)
  while (i < length) {
    // 只要有一個(gè)值不符合callback預(yù)期就返回false
    if (i in this && !callback.call(thisCtx, this[ i ], i, this)) {
      return false
    }

    i++
  }

  return true
}

測(cè)試一把:

還是拿例子做測(cè)試

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 方法測(cè)試數(shù)組中是不是至少有1個(gè)元素通過了被提供的函數(shù)測(cè)試。它返回的是一個(gè)Boolean類型的值。 mdn

注意點(diǎn):

  • callback 只會(huì)在那些”有值“的索引上被調(diào)用,不會(huì)在那些被刪除或從來未被賦值的索引上調(diào)用。

舉個(gè)例子

let emptyArr = []
// 空數(shù)組直接返回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

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

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) {
    // 只要有一個(gè)元素符合callback條件,就返回true
    if (i in this && callback.call(thisCtx, this[ i ], i, this)) {
      return true
    }

    i++
  }

  return false
}

測(cè)試一把:

let emptyArr = []
// 空數(shù)組直接返回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 方法創(chuàng)建一個(gè)新數(shù)組, 其包含通過所提供函數(shù)測(cè)試的所有元素。 mdn

注意點(diǎn):

  • filter 為數(shù)組中的每個(gè)元素調(diào)用一次 callback 函數(shù),并利用所有使得 callback 返回 true 或等價(jià)于 true 的值的元素創(chuàng)建一個(gè)新數(shù)組。
  • callback 只會(huì)在已經(jīng)賦值的索引上被調(diào)用,對(duì)于那些已經(jīng)被刪除或者從未被賦值的索引不會(huì)被調(diào)用。
  • 那些沒有通過 callback 測(cè)試的元素會(huì)被跳過,不會(huì)被包含在新數(shù)組中。
// 索引為5的位置,沒有初始化值,不會(huì)被遍歷
let arr = [ 0, 1, 2, -3, 4,, 5 ]
// 刪除掉最后一個(gè)元素
delete arr[6]
// 過濾出大于0的值
let filterArr = arr.filter((it) => it > 0)

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

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

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
}

測(cè)試:

// 索引為5的位置,沒有初始化值,不會(huì)被遍歷
let arr = [ 0, 1, 2, -3, 4,, 5 ]
// 刪除掉最后一個(gè)元素
delete arr[6]
// 過濾出大于0的值
let filterArr = arr.filter2((it) => it > 0)

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

6. reduce

基本使用:

reduce 方法對(duì)數(shù)組中的每個(gè)元素執(zhí)行一個(gè)由您提供的reducer函數(shù)(升序執(zhí)行),將其結(jié)果匯總為單個(gè)返回值 mdn

這個(gè)函數(shù)稍微復(fù)雜一些,我們用一個(gè)例子來看一下他是怎么用的。

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

console.log(sum) // 10

// 初始設(shè)置
prev = initialValue = 1, cur = 2

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

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

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

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

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
  // 當(dāng)沒有傳遞初始值時(shí),取第一個(gè)作為初始值  
  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
}

測(cè)試:

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

console.log(sum) // 10

7. reduceRight

基本使用:

reduceRight 方法對(duì)數(shù)組中的每個(gè)元素執(zhí)行一個(gè)由您提供的reducer函數(shù)(降序執(zhí)行),將其結(jié)果匯總為單個(gè)返回值 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

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

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

  let pre = initValue
  const length = this.length
  // 從最后一個(gè)元素開始遍歷
  let i = length - 1
  // 如果沒有傳遞初始值,則取最后一個(gè)作為初始值
  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
}

測(cè)試:

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 方法返回?cái)?shù)組中滿足測(cè)試函數(shù)的第一個(gè)元素的值。否則返回 undefined, mdn

注意點(diǎn):

  • find方法對(duì)數(shù)組中的每一項(xiàng)元素執(zhí)行一次 callback 函數(shù),直至有一個(gè) callback 返回 true
  • 當(dāng)找到了這樣一個(gè)元素后,該方法會(huì)立即返回這個(gè)元素的值,否則返回 undefined
  • callback 函數(shù)會(huì)為數(shù)組中的每個(gè)索引調(diào)用即從 0 到 length - 1,而不僅僅是那些被賦值的索引。(這個(gè)點(diǎn)是和前面幾個(gè)函數(shù)不一樣的地方)
let arr = [ 0, 1, 2, 3, 4,, 5 ]

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

console.log(index) // 4

代碼實(shí)現(xiàn):

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 ]
    // 只要有一個(gè)元素符合callback回調(diào)函數(shù)的邏輯,就返回元素value
    if (callback.call(thisCtx, value, i, this)) {
      return value
    }

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

測(cè)試:

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方法返回?cái)?shù)組中滿足提供的測(cè)試函數(shù)的第一個(gè)元素的索引。若沒有找到對(duì)應(yīng)元素則返回-1。 mdn
  • 和find函數(shù)不同的地方在于,findIndex是返回索引而非值, 注意點(diǎn)也和find基本一樣
  • findIndex方法對(duì)數(shù)組中的每個(gè)數(shù)組索引0 ~ length-1(包括)執(zhí)行一次callback函數(shù),直到找到一個(gè)callback函數(shù)返回true的值。
  • 如果找到這樣的元素,findIndex會(huì)立即返回該元素的索引。如果回調(diào)從不返回真值,或者數(shù)組的length為0,則findIndex返回-1
  • 與某些其他數(shù)組方法(如Array#some)不同,在稀疏數(shù)組中,即使對(duì)于數(shù)組中不存在的條目的索引也會(huì)調(diào)用回調(diào)函數(shù)
let arr = [ 0, 1, 2, 3, 4,, 5 ]

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

console.log(index) // 3

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

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
}

測(cè)試:

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方法返回在數(shù)組中可以找到一個(gè)給定元素的第一個(gè)索引,如果不存在,則返回-1。 mdn

arr.indexOf(searchElement[, fromIndex])

注意點(diǎn):

  • 如果開始查找的索引值大于或等于數(shù)組長(zhǎng)度,意味著不會(huì)在數(shù)組里查找,返回-1
  • 如果參數(shù)中提供的索引值是一個(gè)負(fù)值,則將其作為數(shù)組末尾的一個(gè)抵消,即-1表示從最后一個(gè)元素開始查找,-2表示從倒數(shù)第二個(gè)元素開始查找 ,以此類推
  • 如果參數(shù)中提供的索引值是一個(gè)負(fù)值,并不改變其查找順序,查找順序仍然是從前向后查詢數(shù)組
  • 如果抵消后的索引值仍小于0,則整個(gè)數(shù)組都將會(huì)被查詢。其默認(rèn)值為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

代碼實(shí)現(xiàn)

點(diǎn)擊查看源碼實(shí)現(xiàn)

有了上面的注意點(diǎn)和基本你使用,聰明的你肯定一眼就知道怎么寫啦

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

  fromIndex = +fromIndex || 0

  // 數(shù)組為空或者從大于等于數(shù)組長(zhǎng)度的地方開始檢索,都直接是-1
  if (length === 0 || fromIndex >= length) {
    return -1
  }
  /*
    1. 從fromIndex開始搜索元素
    2. fromIndex大于0時(shí)候直接取即可
    3. 小于0先用長(zhǎng)度減去fromIndex的絕對(duì)值,如果還是小于0,就直接取0即可
  */
  let i = Math.max(fromIndex >= 0 ? fromIndex : length - Math.abs(fromIndex), 0)

  while (i < length) {
    // 在數(shù)組內(nèi)的元素并且和targetEle強(qiáng)等
    if (i in this && targetEle === this[ i ]) {
      return i
    }

    i++
  }

  return -1
}

測(cè)試:

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 方法返回指定元素在數(shù)組中的最后一個(gè)的索引,如果不存在則返回 -1。 mdn

arr.lastIndexOf(searchElement[, fromIndex])

注意點(diǎn):

  • arr.length - 1位置開始逆向查找。
  • 如果fromIndex大于或等于數(shù)組的長(zhǎng)度,則整個(gè)數(shù)組會(huì)被查找。
  • 如果fromIndex為負(fù)值,將其視為從數(shù)組末尾向前的偏移。即使該值為負(fù),數(shù)組仍然會(huì)被從后向前查找。
  • 如果fromIndex值為負(fù)時(shí),其絕對(duì)值大于數(shù)組長(zhǎng)度,則方法返回 -1,即數(shù)組不會(huì)被查找。
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

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

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

  fromIndex = typeof fromIndex === 'undefined' ? length - 1 : fromIndex
  // 數(shù)組為空,以及該值為負(fù)時(shí)且絕對(duì)值大于數(shù)組長(zhǎng)度,則方法返回 -1,即數(shù)組不會(huì)被查找。
  if (length === 0 || fromIndex < 0 && Math.abs(fromIndex) >= length) {
    return -1
  }

  let i

  if (fromIndex >= 0) {
    // 如果`fromIndex`大于或等于數(shù)組的長(zhǎng)度,則整個(gè)數(shù)組會(huì)被查找。
    // 也就是當(dāng)大于數(shù)組length - 1時(shí),會(huì)取length - 1
    i = Math.min(fromIndex, length - 1)
  } else {
    i = length - Math.abs(fromIndex)
  }

  while (i >= 0) {
    // 等于targetEle時(shí)返回索引
    if (i in this && targetEle === this[ i ]) {
      return i
    }
    // 逆向遍歷
    i--
  }
  // 沒找到返回-1
  return -1
}

測(cè)試:

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 方法用來判斷一個(gè)數(shù)組是否包含一個(gè)指定的值,如果包含則返回 true,否則返回false。mdn

arr.includes(valueToFind[, fromIndex])

注意點(diǎn):

  • 從fromIndex 索引處開始查找 valueToFind。
  • 如果為負(fù)值,則按升序從 array.length + fromIndex 的索引開始搜
  • 數(shù)組中存在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

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

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

  fromIndex = +fromIndex || 0

  // 數(shù)組為空或者從大于等于數(shù)組長(zhǎng)度的地方開始檢索,都直接是-1
  if (length === 0 || fromIndex >= length) {
    return false
  }
  /*
    1. 從fromIndex開始搜索元素
    2. fromIndex大于0時(shí)候直接取即可
    3. 小于0先用長(zhǎng)度減去fromIndex的絕對(duì)值,如果還是小于0,就直接取0即可
  */
  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
}

測(cè)試:

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 方法將一個(gè)或多個(gè)元素添加到數(shù)組的末尾,并返回該數(shù)組的新長(zhǎng)度。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

代碼實(shí)現(xiàn)

點(diǎn)擊查看源碼實(shí)現(xiàn)

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
}

測(cè)試:

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方法從數(shù)組中刪除最后一個(gè)元素,并返回該元素的值。此方法更改數(shù)組的長(zhǎng)度。mdn

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

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

代碼實(shí)現(xiàn)和使用一樣簡(jiǎn)單,只要把數(shù)組的最后一個(gè)元素返回,并且讓數(shù)組長(zhǎng)度減1即可

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

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

  const delEle = this[ length - 1 ]

  this.length = length - 1

  return delEle
}

測(cè)試:

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

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

3. unshift

基本使用:

unshift  方法將一個(gè)或多個(gè)元素添加到數(shù)組的開頭,并返回該數(shù)組的新長(zhǎng)度(該方法修改原有數(shù)組 ) 。

注意點(diǎn):

  • 如果傳入多個(gè)參數(shù),它們會(huì)被以塊的形式插入到對(duì)象的開始位置,它們的順序和被作為參數(shù)傳入時(shí)的順序一致。
  • 傳入多個(gè)參數(shù)調(diào)用一次 unshift ,和傳入一個(gè)參數(shù)調(diào)用多次 unshift (例如,循環(huán)調(diào)用),它們將得到不同的結(jié)果。

例如:

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]

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

Array.prototype.unshift2 = function (...unshiftEles) {
  // 借助擴(kuò)展符,將需要添加的元素以塊的形式插入到數(shù)組前面
  let newArray = [ ...unshiftEles, ...this ]
  let length = newArray.length
  
  let i = 0

  if (unshiftEles.length === 0) {
    return length
  }
  // 重新復(fù)制給數(shù)組
  while (i < length) {
    this[ i ] = newArray[ i ]
    i++
  }
  
  return this.length
}

測(cè)試:

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 方法從數(shù)組中刪除第一個(gè)元素,并返回該元素的值。 mdn

let arr = [ 1, 2 ]

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

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

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

  let i = 1

  while (i < length) {
    // 從第一個(gè)元素開始,后面的元素都往前移動(dòng)一位
    this[ i - 1 ] = this[ i ]
    i++
  }
  // 設(shè)置好數(shù)組的長(zhǎng)度
  this.length = length - 1
  // 返回刪除的值
  return delValue
}

測(cè)試:

let arr = [ 1, 2 ]

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

5. reverse

基本使用:

reverse 方法將數(shù)組中元素的位置顛倒,并返回該數(shù)組。即數(shù)組的第一個(gè)元素會(huì)變成最后一個(gè),數(shù)組的最后一個(gè)元素變成第一個(gè)。mdn

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

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

arr.reverse()

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

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

Array.prototype.reverse2 = function () {
  // 設(shè)置雙指針,往中間靠攏
  let i = 0
  let j = this.length - 1

  while (i < j) {
    // 第一個(gè)和最后一個(gè),第二個(gè)和倒數(shù)第二個(gè)進(jìn)行位置調(diào)換
    [ this[ i ], this[ j ] ] = [ this[ j ], this[ i ] ]
    i++
    j--
  }

  return this
}

測(cè)試:

const arr = [1, 2, 3]

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

arr.reverse2()

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

6. fill

基本使用:

fill 方法用一個(gè)固定值填充一個(gè)數(shù)組中從起始索引到終止索引內(nèi)的全部元素。不包括終止索引。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]

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

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

  start = start >> 0
  // end沒填的話,默認(rèn)是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++
  }
  // 返回被修改的數(shù)組
  return this
}

測(cè)試:

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 方法用于合并兩個(gè)或多個(gè)數(shù)組。此方法不會(huì)更改現(xiàn)有數(shù)組,而是返回一個(gè)新數(shù)組 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]]

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

Array.prototype.concat2 = function (...concatEles) {
  const length = concatEles.length
  // 數(shù)組本身展開一層
  let newArray = [ ...this ]
  let i = 0

  while (i < length) {
    const value = concatEles[ i ]
    // 對(duì)數(shù)組元素展開一層 
    Array.isArray(value) ? newArray.push(...value) : newArray.push(value)
    i++
  }

  return newArray
}

測(cè)試:

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 方法將一個(gè)數(shù)組的所有元素通過字符標(biāo)識(shí)連接成一個(gè)字符串并返回這個(gè)字符串。如果數(shù)組只有一個(gè)項(xiàng)目,那么將返回該項(xiàng)目而不使用分隔符。

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

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

Array.prototype.join2 = function (format = ',') {
  const length = this.length
  // 保存最后一個(gè)元素,因?yàn)樗粎⑴cformat連接 
  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
}

 測(cè)試:

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

四、靜態(tài)方法

1. Array.isArray

基本使用:

Array.isArray() 用于確定傳遞的值是否是一個(gè) Array。

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

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

Array.isArray("foobar") // false

Array.isArray(undefined) // false

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

這個(gè)非常簡(jiǎn)單,只需要一句話就可以

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

測(cè)試:

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

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

Array.isArray2("foobar") // false

Array.isArray2(undefined) // false

2. Array.of

基本使用:

Array.of 方法創(chuàng)建一個(gè)具有可變數(shù)量參數(shù)的新數(shù)組實(shí)例,而不考慮參數(shù)的數(shù)量或類型。

注意點(diǎn):

  • Array.of()  和 Array 構(gòu)造函數(shù)之間的區(qū)別在于處理整數(shù)參數(shù):
  • Array.of(7) 創(chuàng)建一個(gè)具有單個(gè)元素 7 的數(shù)組,而 Array(7) 創(chuàng)建一個(gè)長(zhǎng)度為7的空數(shù)組(注意: 這是指一個(gè)有7個(gè)空位(empty)的數(shù)組,而不是由7個(gè)undefined組成的數(shù)組)
Array.of(7);       // [7]
Array.of(1, 2, 3); // [1, 2, 3]

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

代碼實(shí)現(xiàn):

擊查看源碼實(shí)現(xiàn)

實(shí)現(xiàn)思路就是把你穿進(jìn)去的值,挨個(gè)賦值到當(dāng)前數(shù)組即可

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

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

  return newArray
}

測(cè)試:

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

五、扁平類

1. flat

基本使用:

flat()  方法會(huì)按照一個(gè)可指定的深度遞歸遍歷數(shù)組,并將所有元素與遍歷到的子數(shù)組中的元素合并為一個(gè)新數(shù)組返回。 mdn

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

console.log(arr1.flat()) // [0, 1, 2, 3, 4] 默認(rèn)會(huì)平鋪展開一層


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

console.log(arr2.flat(2)) // [0, 1, 2, [3, 4]] 指定展開兩層

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

Array.prototype.flat2 = function (depth = 1) {
  const result = []
  const flat = (arr, depth) => {
    for (let item of arr) {
      // 當(dāng)層數(shù)還未全部展開的時(shí)候,進(jìn)行遞歸處理
      if (Array.isArray(item) && depth > 0) {
        flat(item, depth - 1)
      } else {
        // 去除空元素,添加非undefined元素
        item !== void 0 && result.push(item)
      }
    }
  }

  flat(this, depth)

  return result
}

測(cè)試:

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 方法首先使用映射函數(shù)映射每個(gè)元素,然后將結(jié)果壓縮成一個(gè)新數(shù)組。它與 map 連著深度值為1的 flat 幾乎相同。 mdn

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


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

代碼實(shí)現(xiàn):

點(diǎn)擊查看源碼實(shí)現(xiàn)

Array.prototype.flatMap2 = function (callback, thisCtx) {
  if (typeof callback !== 'function') {
    throw `${callback} is not a function`
  }
  // map和flat具體實(shí)現(xiàn)可以看map.js和flat.js
  return this.map(function (it, i, array) {
    return callback.call(thisCtx, it, i, array)
  }).flat(1)
}

測(cè)試:

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


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

結(jié)尾:

到此這篇關(guān)于徒手實(shí)現(xiàn)關(guān)于JavaScript的24+數(shù)組方法的文章就介紹到這了,更多相關(guān)實(shí)現(xiàn)關(guān)于JavaScript的24+數(shù)組方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

國慶將至,祝大家節(jié)日快樂,浪浪浪七天樂。

相關(guān)文章

最新評(píng)論