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

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

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

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

一、遍歷類

1. forEach

基本使用:

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

  • 該方法對數(shù)組的每個元素執(zhí)行一次給定的函數(shù),返回值是undefiend
  • 該方法按升序為數(shù)組中含有效值的每一項執(zhí)行一次 callback 函數(shù),未初始化的項將被跳過(例如在稀疏數(shù)組上)。
  • 如果已經(jīng)存在的值被改變,則傳遞給 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)
})

/*
 1
 2
 3
 4-4
 5
*/

代碼實現(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),所以不會被訪問到
    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)
})

/*
 1
 2
 3
 4-4
 5
*/

2. map

基本使用:

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

注意點:

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

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

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

代碼實現(xiàn):

點擊查看源碼實現(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返回值是一個新的數(shù)組
  let newArray = []

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

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

注意點:

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

代碼實現(xiàn):

點擊查看源碼實現(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án)
  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 方法測試數(shù)組中是不是至少有1個元素通過了被提供的函數(shù)測試。它返回的是一個Boolean類型的值。 mdn

注意點:

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

舉個例子

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

代碼實現(xiàn):

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

    i++
  }

  return false
}

測試一把:

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)建一個新數(shù)組, 其包含通過所提供函數(shù)測試的所有元素。 mdn

注意點:

  • filter 為數(shù)組中的每個元素調用一次 callback 函數(shù),并利用所有使得 callback 返回 true 或等價于 true 的值的元素創(chuàng)建一個新數(shù)組。
  • callback 只會在已經(jīng)賦值的索引上被調用,對于那些已經(jīng)被刪除或者從未被賦值的索引不會被調用。
  • 那些沒有通過 callback 測試的元素會被跳過,不會被包含在新數(shù)組中。
// 索引為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 ]

代碼實現(xiàn):

點擊查看源碼實現(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
}

測試:

// 索引為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 方法對數(shù)組中的每個元素執(zhí)行一個由您提供的reducer函數(shù)(升序執(zhí)行),將其結果匯總為單個返回值 mdn

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

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 (退出)

代碼實現(xiàn):

點擊查看源碼實現(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
  // 當沒有傳遞初始值時,取第一個作為初始值  
  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 方法對數(shù)組中的每個元素執(zhí)行一個由您提供的reducer函數(shù)(降序執(zhí)行),將其結果匯總為單個返回值 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

代碼實現(xiàn):

點擊查看源碼實現(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
  // 從最后一個元素開始遍歷
  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 方法返回數(shù)組中滿足測試函數(shù)的第一個元素的值。否則返回 undefined, mdn

注意點:

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

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

console.log(index) // 4

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

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

console.log(index) // 3

代碼實現(xiàn):

點擊查看源碼實現(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
}

測試:

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

arr.indexOf(searchElement[, fromIndex])

注意點:

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

代碼實現(xiàn)

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

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

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

  fromIndex = +fromIndex || 0

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

  while (i < length) {
    // 在數(shù)組內(nèi)的元素并且和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 方法返回指定元素在數(shù)組中的最后一個的索引,如果不存在則返回 -1。 mdn

arr.lastIndexOf(searchElement[, fromIndex])

注意點:

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

代碼實現(xiàn):

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

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

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

  let i

  if (fromIndex >= 0) {
    // 如果`fromIndex`大于或等于數(shù)組的長度,則整個數(shù)組會被查找。
    // 也就是當大于數(shù)組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 方法用來判斷一個數(shù)組是否包含一個指定的值,如果包含則返回 true,否則返回false。mdn

arr.includes(valueToFind[, fromIndex])

注意點:

  • 從fromIndex 索引處開始查找 valueToFind
  • 如果為負值,則按升序從 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

代碼實現(xiàn):

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

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

  fromIndex = +fromIndex || 0

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

測試:

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

代碼實現(xiàn)

點擊查看源碼實現(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
}

測試:

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

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

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

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

代碼實現(xiàn):

點擊查看源碼實現(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
}

測試:

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

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

3. unshift

基本使用:

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

注意點:

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

例如:

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]

代碼實現(xiàn):

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

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

  if (unshiftEles.length === 0) {
    return length
  }
  // 重新復制給數(shù)組
  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 方法從數(shù)組中刪除第一個元素,并返回該元素的值。 mdn

let arr = [ 1, 2 ]

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

代碼實現(xiàn):

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

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

  let i = 1

  while (i < length) {
    // 從第一個元素開始,后面的元素都往前移動一位
    this[ i - 1 ] = this[ i ]
    i++
  }
  // 設置好數(shù)組的長度
  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 方法將數(shù)組中元素的位置顛倒,并返回該數(shù)組。即數(shù)組的第一個元素會變成最后一個,數(shù)組的最后一個元素變成第一個。mdn

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

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

arr.reverse()

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

代碼實現(xiàn):

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

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

  while (i < j) {
    // 第一個和最后一個,第二個和倒數(shù)第二個進行位置調換
    [ 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 方法用一個固定值填充一個數(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]

代碼實現(xiàn):

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

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

代碼實現(xiàn):

點擊查看源碼實現(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 ]
    // 對數(shù)組元素展開一層 
    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 方法將一個數(shù)組的所有元素通過字符標識連接成一個字符串并返回這個字符串。如果數(shù)組只有一個項目,那么將返回該項目而不使用分隔符。

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

代碼實現(xiàn):

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

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

四、靜態(tài)方法

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

代碼實現(xiàn):

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

這個非常簡單,只需要一句話就可以

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 方法創(chuàng)建一個具有可變數(shù)量參數(shù)的新數(shù)組實例,而不考慮參數(shù)的數(shù)量或類型。

注意點:

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

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

代碼實現(xiàn):

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

實現(xiàn)思路就是把你穿進去的值,挨個賦值到當前數(shù)組即可

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()  方法會按照一個可指定的深度遞歸遍歷數(shù)組,并將所有元素與遍歷到的子數(shù)組中的元素合并為一個新數(shù)組返回。 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]] 指定展開兩層

代碼實現(xiàn):

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

Array.prototype.flat2 = function (depth = 1) {
  const result = []
  const flat = (arr, depth) => {
    for (let item of arr) {
      // 當層數(shù)還未全部展開的時候,進行遞歸處理
      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 方法首先使用映射函數(shù)映射每個元素,然后將結果壓縮成一個新數(shù)組。它與 map 連著深度值為1的 flat 幾乎相同。 mdn

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


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

代碼實現(xiàn):

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

Array.prototype.flatMap2 = function (callback, thisCtx) {
  if (typeof callback !== 'function') {
    throw `${callback} is not a function`
  }
  // map和flat具體實現(xiàn)可以看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]

結尾:

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

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

相關文章

最新評論