模擬 javaScript Array 原型上的方法

_落雨_發表於2019-04-13

模擬 javaScript Array 原型上的方法

Array.prototype.push

let arr = [1,2,3,4,5]
let arrLike = {0:1,1:2,length:2}
let obj = {}
/**
 * Array.prototype.push(element1,...,elementN)
 * 向陣列末尾新增N個元素並且返回陣列長度
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/push
 * push 方法有意具有通用性。該方法和 call() 或 apply() 一起使用時,
 * 可應用在類似陣列的物件上。push 方法根據 length 屬性來決定從哪裡開始插入給定的值。
 * 如果 length 不能被轉成一個數值,則插入的元素索引為 0,
 * 包括 length 不存在時。當 length 不存在時,將會建立它。
 */
Array.prototype.myPush = function() {
  var length = this.length ? this.length : (this.length = 0) && 0
  var index = 0
  while (index < arguments.length) {
    this[length] = arguments[index]
    ++index
    ++length
  }
  this.length = length
  return this.length
}
arr.myPush(1,2,3,4)
Array.prototype.myPush.call(obj,1,2,{}) 
Array.prototype.myPush.call(arrLike,3,4,{})
console.log(arr)
console.log(obj)
console.log(arrLike)
複製程式碼

Array.prototype.pop

/**
 * Array.prototype.pop()
 * 向陣列末尾刪除元素並且返回該元素
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/pop
 * 從陣列中刪除的元素(當陣列為空時返回undefined)
 * pop 方法有意具有通用性。該方法和 call() 或 apply() 一起使用時,可應用在類似陣列的物件上。
 * pop方法根據 length屬性來確定最後一個元素的位置。
 * 如果不包含length屬性或length屬性不能被轉成一個數值,會將length置為0,並返回undefined。
 */
Array.prototype.myPop = function () {
  var length = this.length ? this.length : (this.length = 0) && 0
  if(length === 0)return
  var last = this[length-1]
  delete this[length - 1]
  --this.length
  return last
}
console.log(Array.prototype.myPop.call(arr))
console.log(Array.prototype.myPop.call(arrLike))
console.log(arr,obj,arrLike)
複製程式碼

Array.prototype.shift

/** 
 * Array.prototype.shift()
 * 向陣列索引為0的位置刪除元素並且返回該元素
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/shift
 * shift 方法移除索引為 0 的元素(即第一個元素),並返回被移除的元素,
 * 其他元素的索引值隨之減 1。如果 length 屬性的值為 0 (長度為 0),則返回 undefined。
 * shift 方法並不侷限於陣列:這個方法能夠通過 call 或 apply 方法作用於類似陣列的物件上。
 * 但是對於沒有 length 屬性(從0開始的一系列連續的數字屬性的最後一個)的物件,呼叫該方法可能沒有任何意義。
 * 
*/ 
Array.prototype.myShift = function(){
  var length = this.length ? this.length : 0
  if(length === 0)return
  var first = this[0]
  var index = 1
  while (index < this.length) {
    this[index - 1] = this[index]
    index ++
  }
  delete this[length - 1]
  --this.length
  return first
}
console.log(arr.myShift())
console.log(Array.prototype.myShift.call(obj))
console.log(Array.prototype.myShift.call(arrLike))
複製程式碼

Array.prototype.unshift

/** 
 * Array.prototype.unshift(element1,...,elementN)
 * 向陣列索引為0的位置插入N個元素並且返回該陣列長度
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift
 * unshift 方法會在呼叫它的類陣列物件的開始位置插入給定的引數。
 * unshift 特意被設計成具有通用性;這個方法能夠通過 call 或 apply 方法作用於類陣列物件上。
 * 不過對於沒有 length 屬性(代表從0開始的一系列連續的數字屬性的最後一個)的物件,呼叫該方法可能沒有任何意義。
 * 
*/ 
Array.prototype.myUnshift = function() {
  if(!this.length)return
  var length = this.length
  var arglength = arguments.length
  this.length = length + arglength
  var index = length - 1
  while (index >= 0) {
    this[index + arglength] = this[index]
    --index
  }
  index = arglength - 1
  while (index >= 0) {
    this[index] = arguments[index]
    --index
  }
  return this.length
}
console.log(arr.myUnshift(0,1,3,4,5))
console.log(Array.prototype.myUnshift.call(obj,0,1,3,4,5))
console.log(Array.prototype.myUnshift.call(arrLike,0,1,3,4,5))
複製程式碼

Array.prototype.slice

/** 
 * Array.prototype.slice(begin,end)
 * 方法返回一個新的陣列物件,這一物件是一個由 begin和 end(不包括end)決定的原陣列的淺拷貝。原始陣列不會被改變。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
 * slice 不修改原陣列,只會返回一個淺複製了原陣列中的元素的一個新陣列。原陣列的元素會按照下述規則拷貝:
 * 如果該元素是個物件引用 (不是實際的物件),slice 會拷貝這個物件引用到新的陣列裡。
 * 兩個物件引用都引用了同一個物件。如果被引用的物件發生改變,則新的和原來的陣列中的這個元素也會發生改變。
 * 對於字串、數字及布林值來說(不是 String、Number 或者 Boolean 物件),slice 會拷貝這些值到新的陣列裡。
 * 在別的陣列裡修改這些字串或數字或是布林值,將不會影響另一個陣列。
 * 
*/ 
Array.prototype.mySlice = function(begin,end) {
  if(!this.length)return
  var arr = []
  var index = 0
  begin = typeof begin === 'number' ? 
        begin < 0 ? this.length + begin 
        : begin 
        : 0
  end =  typeof end === 'number' ? 
        end > this.length ? this.length 
        : end 
        : this.length
  while (begin < end) {
    arr[index] = this[begin]
    begin++
    index++
  }
  return arr
}
console.log(arr.mySlice(-4))
console.log(Array.prototype.mySlice.call(obj,0,2))
console.log(Array.prototype.mySlice.call(arrLike,0,1))
複製程式碼

Array.prototype.concat

/** 
 * Array.prototype.concat(item1,...,itemN)
 * 方法返回一個新的陣列物件,這一物件是一個由 begin和 end(不包括end)決定的原陣列的淺拷貝。原始陣列不會被改變。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/concat
 * concat方法建立一個新的陣列,它由被呼叫的物件中的元素組成,
 * 每個引數的順序依次是該引數的元素(如果引數是陣列)或引數本身(如果引數不是陣列)。它不會遞迴到巢狀陣列引數中。
 * concat方法不會改變this或任何作為引數提供的陣列,而是返回一個淺拷貝
 * 
*/ 
Array.prototype.myConcat = function() {
  if(!arguments.length)return
  var arr = []
  var index = 0
  while (index<this.length) {
    arr[index] = this[index]
    ++index
  }
  var i = 0
  while (i < arguments.length) {
    var el = arguments[i]
    if(el instanceof Array) {
      if(el.length){
        var j = 0
        while (j < el.length) {
          arr[index] = el[j]
          ++index
          ++j
        }
      }
    }else{
      arr[index] = el
      ++index
    }
    ++i
  }
  return arr
}
console.log(arr.myConcat(1,[2,3],[4,[5,[6],[7]]]))
console.log(arr.concat(1,[2,3],[4,[5,[6],[7]]]))
console.log(arr)
複製程式碼

Array.prototype.splice

/** 
 * Array.prototype.splice(start,deleteCount,item1,...,itemN)
 * 方法通過刪除或替換現有元素來修改陣列,並以陣列形式返回被修改的內容。此方法會改變原陣列。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
 * 如果新增進陣列的元素個數不等於被刪除的元素個數,陣列的長度會發生相應的改變。
 * 
*/ 
Array.prototype.mySplice = function(start,deleteCount) {
  if(!this.length)return
  var arr = []
  /**
   * 如果超出了陣列的長度,則從陣列末尾開始新增內容;
   * 如果是負值,則表示從陣列末位開始的第幾位(從-1計數);
   * 如果負數的絕對值大於陣列的長度,則表示開始位置為第0位。
   */
  start = typeof start === 'number' ?
          start > this.length ? this.length 
        : start < 0 ? this.length + start < 0 ? 0 
        : this.length + start 
        : start 
        : 0
  /** 
   * 如果 deleteCount 大於 start 之後的元素的總數,則從 start 後面的元素都將被刪除(含第 start 位)。
   * 如果 deleteCount 被省略,則其相當於 array.length - start。
   * 如果 deleteCount 被省略了,或者它的值大於等於array.length - start(也就是說,如果它大於或者等於start之後的所有元素的數量),那麼start之後陣列的所有元素都會被刪除。
   * 如果 deleteCount 是 0 或者負數,則不移除元素。這種情況下,至少應新增一個新元素。
  */
  deleteCount = typeof deleteCount === 'number' ? 
              deleteCount < 0 ? 0 
            : deleteCount > this.length - start ? this.length - start 
            : deleteCount : deleteCount === undefined ? this.length - start 
            : 0
  //取出除去前兩個引數之後的剩餘引數
  var args = arguments.length > 2 ? Array.prototype.mySlice.call(arguments,2) : []
  var argLength = args.length

  //記錄一下開始位置
  var oIndex = start
  //需要新增或者縮減的數目
  var moveLength = argLength - deleteCount
  //需要刪除到指定的下標
  var delIndex = deleteCount + start
  //新增到指定的下表
  var addIndex = argLength + start
  var index = 0
  //刪除 [...start, ... ,delIndex,...]
  while (start < delIndex) {
    arr[index] = this[start]
    this[start] = null
    ++start
    ++index
  }
  if(moveLength > 0){
    //陣列不足以插入的時候,開闢新的位置
    var i = this.length - 1
    this.length += moveLength
    while (i >= oIndex) {
      this[i+moveLength] = this[i]
      --i
    }
  }else{
    //插入後還有剩餘,需要回縮空間
    var i = this.length
    if(start < this.length){
      while (start < i) {
        this[start+moveLength] = this[start]
        ++start
      }
    }
    this.length += moveLength
  }
  var i = 0
  // 插入新的 item1...itemN
  while (oIndex < addIndex) {
    this[oIndex] = args[i]
    ++i
    ++oIndex
  }
  return arr
}
console.log(arrLike)
console.log(Array.prototype.mySplice.call(arrLike,1,1))
console.log(arrLike)
console.log(arr.mySplice())
console.log(arr)
複製程式碼

Array.prototype.reduce

/**
 * Array.prototype.reduce(callback,initialValue)
 * reduce() 方法對陣列中的每個元素執行一個由您提供的reducer函式(升序執行),將其結果彙總為單個返回值。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
 * callback 執行陣列中每個值的函式,包含四個引數:
  * accumulator: 累計器累計回撥的返回值; 它是上一次呼叫回撥時返回的累積值,或initialValue(見於下方)。
  * currentValue: 陣列中正在處理的元素。
  * currentIndex可選: 陣列中正在處理的當前元素的索引。 如果提供了initialValue,則起始索引號為0,否則為1。
  * array可選: 呼叫reduce()的陣列
 * initialValue 可選
 * 作為第一次呼叫 callback函式時的第一個引數的值。 如果沒有提供初始值,則將使用陣列中的第一個元素。 在沒有初始值的空陣列上呼叫 reduce 將報錯。
 */
Array.prototype.myReduce = function(callback){
  var arr = this.mySlice()
  var len = arr.length
  var index = 0
  var initialValue
  if(arguments.length >= 2){
    //如果有預設值取預設值
    initialValue = arguments[1] 
  }else{
    //如果沒有預設值,取第一個有值的索引,處理稀疏陣列,若第一項沒有值的時候起始索引往後走
    while (index < len && !(arr[index] in arr)) {
      ++index
    }
    if(index >= len) return
    initialValue = arr[index++]
  }
  while (index < len) {
    if(arr[index] in arr){
      //值存在才走進來
      initialValue = callback.call(null, initialValue, arr[index], index, arr)
    }
    ++index
  }
  return initialValue
}
var sum = [0,1,2,3,4].myReduce(function(accumulator, currentValue, currentIndex, array){
  console.log(accumulator, currentValue, currentIndex, array)
  return accumulator + currentValue;
}); // 10
var sum = [, 1, ,3,,].myReduce(function(accumulator, currentValue, currentIndex, array){
  console.log(accumulator, currentValue, currentIndex, array)
  return accumulator + currentValue;
}); // 4
複製程式碼

Array.prototype.reduceRight

/**
 * Array.prototype.reduceRight(callback,initialValue)
 * reduceRight() 方法對陣列中的每個元素執行一個由您提供的reducer函式(降序執行),將其結果彙總為單個返回值。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight
 * callback 執行陣列中每個值的函式,包含四個引數:
  * accumulator: 累計器累計回撥的返回值; 它是上一次呼叫回撥時返回的累積值,或initialValue(見於下方)。
  * currentValue: 陣列中正在處理的元素。
  * currentIndex可選: 陣列中正在處理的當前元素的索引。 如果提供了initialValue,則起始索引號為0,否則為1。
  * array可選: 呼叫reduceRight()的陣列
 * initialValue 可選
 * 作為第一次呼叫 callback函式時的第一個引數的值。 如果沒有提供初始值,則將使用陣列中的第一個元素。 在沒有初始值的空陣列上呼叫 reduceRight 將報錯。
 */
Array.prototype.myReduceRight = function(callback){
  var arr = this.mySlice()
  var len = arr.length-1
  var index = len
  var initialValue
  if(arguments.length >= 2){
    //如果有預設值取預設值
    initialValue = arguments[1] 
  }else{
    //如果沒有預設值,取第一個有值的索引,處理稀疏陣列,若最後一項項沒有值的時候起始索引往前走
    while (index >= 0 && !(arr[index] in arr)) {
      --index
    }
    if(index <= 0) return
    initialValue = arr[index--]
  }
  while (index >= 0) {
    if(arr[index] in arr){
      //值存在才走進來
      initialValue = callback.call(null, initialValue, arr[index], index, arr)
    }
    index--
  }
  return initialValue
}
var sum = [0,1,2,3,4].myReduceRight(function(accumulator, currentValue, currentIndex, array){
  console.log(accumulator, currentValue, currentIndex, array)
  return accumulator + currentValue;
},2); // 12
var sum = [, 1, ,3,,].myReduceRight(function(accumulator, currentValue, currentIndex, array){
  console.log(accumulator, currentValue, currentIndex, array)
  return accumulator + currentValue;
},2); // 6
複製程式碼

Array.prototype.forEach

/**
 * Array.prototype.forEach(callback,context)
 * forEach() 方法對陣列的每個元素執行一次提供的函式。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
 * callback 生成新陣列元素的函式,使用三個引數:
    * currentValue
      * callback 陣列中正在處理的當前元素。
    * index可選
      * callback 陣列中正在處理的當前元素的索引。
    * array可選
      * callback  map 方法被呼叫的陣列。
  * thisArg可選
    * 執行 callback 函式時使用的this 值。
 */
Array.prototype.myForEach = function(callback){
  var len = this.length
  var index = 0
  var context = arguments[1] || this
  while (index < len) {
    callback.call(context, this[index], index, this)
    index++
  }
}
[1,2,3,4,5].forEach(function(current, index, arr) {
  console.log(current, index, arr, this.a)
},{a:1})
[1,2,3,4,5].myForEach(function(current, index, arr){
  console.log(current, index, arr, this.a)
},{a:1})
複製程式碼

Array.prototype.map

/**
 * Array.prototype.map(callback,context)
 * map() 方法建立一個新陣列,其結果是該陣列中的每個元素都呼叫一個提供的函式後返回的結果。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map
 * callback 生成新陣列元素的函式,使用三個引數:
    * currentValue
      * callback 陣列中正在處理的當前元素。
    * index可選
      * callback 陣列中正在處理的當前元素的索引。
    * array可選
      * callback  map 方法被呼叫的陣列。
  * thisArg可選
    * 執行 callback 函式時使用的this 值。
 */
Array.prototype.myMap = function(callback){
  var arr = []
  var len = this.length
  var index = 0
  var context = arguments[1] || this
  while (index < len) {
    arr.myPush(callback.call(context, this[index], index, this))
    index++
  }
  return arr
}
console.log([1,2,3,4,5].map(function(current, index, arr) {
  console.log(current, index, arr)
  return index + this.a
},{a:1})) //[1,2,3,4,5]
console.log([1,2,3,4,5].myMap(function(current, index, arr) {
  console.log(current, index, arr)
  return index + this.a
},{a:1})) //[1,2,3,4,5]
複製程式碼

Array.prototype.filter

/**
 * Array.prototype.filter(callback,context)
 * filter() 方法建立一個新陣列, 其包含通過所提供函式實現的測試的所有元素。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
 * callback 生成新陣列元素的函式,使用三個引數:
    * currentValue
      * callback 陣列中正在處理的當前元素。
    * index可選
      * callback 陣列中正在處理的當前元素的索引。
    * array可選
      * callback  filter 方法被呼叫的陣列。
  * thisArg可選
    * 執行 callback 函式時使用的this 值。
 */
Array.prototype.myFilter = function(callback){
  var arr = []
  var len = this.length
  var index = 0
  var context = arguments[1] || this
  while (index < len) {
    var el = this[index]
    callback.call(context, el, index, this) && arr.myPush(el)
    index++
  }
  return arr
}
console.log([1,2,3,4,5].filter(function(current, index, arr) {
  console.log(current, index, arr)
  return index > this.a
},{a:1}))
console.log([1,2,3,4,5].myFilter(function(current, index, arr) {
  console.log(current, index, arr)
  return index > this.a
},{a:1}))/**
 * Array.prototype.filter(callback,context)
 * filter() 方法建立一個新陣列, 其包含通過所提供函式實現的測試的所有元素。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
 * callback 生成新陣列元素的函式,使用三個引數:
    * currentValue
      * callback 陣列中正在處理的當前元素。
    * index可選
      * callback 陣列中正在處理的當前元素的索引。
    * array可選
      * callback  filter 方法被呼叫的陣列。
  * thisArg可選
    * 執行 callback 函式時使用的this 值。
 */
Array.prototype.myFilter = function(callback){
  var arr = []
  var len = this.length
  var index = 0
  var context = arguments[1] || this
  while (index < len) {
    var el = this[index]
    callback.call(context, el, index, this) && arr.myPush(el)
    index++
  }
  return arr
}
console.log([1,2,3,4,5].filter(function(current, index, arr) {
  console.log(current, index, arr)
  return index > this.a
},{a:1}))//[3,4,5]
console.log([1,2,3,4,5].myFilter(function(current, index, arr) {
  console.log(current, index, arr)
  return index > this.a
},{a:1}))//[3,4,5]
複製程式碼

Array.prototype.every

/**
 * Array.prototype.every(callback,context)
 * every() 方法測試陣列的所有元素是否都通過了指定函式的測試。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/every
 * callback 生成新陣列元素的函式,使用三個引數:
    * currentValue
      * callback 陣列中正在處理的當前元素。
    * index可選
      * callback 陣列中正在處理的當前元素的索引。
    * array可選
      * callback  every 方法被呼叫的陣列。
  * thisArg可選
    * 執行 callback 函式時使用的this 值。
 */
Array.prototype.myEvery = function(callback){
  var every = true
  var len = this.length
  var index = 0
  var context = arguments[1] || this
  while (index < len) {
    if(!callback.call(context, this[index], index, this)) {
      every = false 
      break 
    }
    index++
  }
  return every
}
console.log([1,2,3,4,5].every(function(current, index, arr) {
  console.log(current, index, arr)
  return current > this.a
},{a:0})) // true
console.log([1,2,3,4,5].myEvery(function(current, index, arr) {
  console.log(current, index, arr)
  return current > this.a
},{a:0})) // true
複製程式碼

Array.prototype.some

/**
 * Array.prototype.some(callback,context)
 * some() 方法測試是否至少有一個元素通過由提供的函式實現的測試。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/some
 * callback 生成新陣列元素的函式,使用三個引數:
    * currentValue
      * callback 陣列中正在處理的當前元素。
    * index可選
      * callback 陣列中正在處理的當前元素的索引。
    * array可選
      * callback  some 方法被呼叫的陣列。
  * thisArg可選
    * 執行 callback 函式時使用的this 值。
 */
Array.prototype.mySome = function(callback){
  var every = false
  var len = this.length
  var index = 0
  var context = arguments[1] || this
  while (index < len) {
    if(callback.call(context, this[index], index, this)) {
      every = true 
      break 
    }
    index++
  }
  return every
}
console.log([1,2,3,4,5].some(function(current, index, arr) {
  console.log(current, index, arr)
  return current > this.a
},{a:10})) // false
console.log([1,2,3,4,5].mySome(function(current, index, arr) {
  console.log(current, index, arr)
  return current > this.a
},{a:10})) // false
複製程式碼

Array.prototype.find

/**
 * arr.find(callback[, thisArg]) 方法返回陣列中滿足提供的測試函式的第一個元素的值。否則返回 undefined。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/find
 * callback
  * 在陣列每一項上執行的函式,接收 3 個引數:
 * element
  * 當前遍歷到的元素。
 * index可選
  * 當前遍歷到的索引。
 * array可選
  * 陣列本身。
 * thisArg可選
  * 執行回撥時用作this 的物件。
*/
Array.prototype.myFind = function(callback,context) {
  context = context || window
  var len = this.length
  var i = 0
  while (i < len) {
    if(callback.call(context,this[i],i,this))
      return this[i]
    i++
  }
  return undefined
}
console.log([4, 6, 8, 12].myFind(function(item) {
  return item + this.a > 10
},{a:5})); // 6
console.log([4, 6, 8, 12].find(function(item) {
  return item + this.a > 10
},{a:5})); // 6
複製程式碼

Array.prototype.findIndex

/**
 * arr.findIndex(callback[, thisArg]) 方法返回陣列中滿足提供的測試函式的第一個元素的索引。否則返回-1
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
 * callback
  * 在陣列每一項上執行的函式,接收 3 個引數:
 * element
  * 當前遍歷到的元素。
 * index可選
  * 當前遍歷到的索引。
 * array可選
  * 陣列本身。
 * thisArg可選
  * 執行回撥時用作this 的物件。
*/
Array.prototype.myFindIndex = function(callback,context) {
  context = context || window
  var len = this.length
  var i = 0
  while (i < len) {
    if(callback.call(context,this[i],i,this))
      return i
    i++
  }
  return -1
}
console.log([4, 6, 8, 12].myFindIndex(function(item) {
  return item + this.a > 10
},{a:5})); // 1
console.log([4, 6, 8, 12].findIndex(function(item) {
  return item + this.a > 10
},{a:5})); // 1
複製程式碼

Array.prototype.join

/**
 * Array.prototype.join(separator)
 * join() 方法將一個陣列(或一個類陣列物件)的所有元素連線成一個字串並返回這個字串。如果陣列只有一個專案,那麼將返回該專案而不使用分隔符。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/join
 * separator 
 * 指定一個字串來分隔陣列的每個元素。如果需要,將分隔符轉換為字串。
 * 如果省略(),陣列元素用逗號分隔。預設為 ","。如果separator是空字串(""),則所有元素之間都沒有任何字元。
 */
Array.prototype.myJoin = function(separator){
  var separator = typeof separator === 'string' ? separator : ','
  var len = this.length
  var str = ''
  if(!len) return str
  var index = 1
  str = this[0]  ? this[0].toString() : '' 
  while (index < len) {
    str += separator + (this[index] ? this[index].toString() : '')
    index++
  }
  return str
}
console.log([1,null,,{},[],/2/].myJoin(',') === [1,null,,{},[],/2/].join(',')) //true

複製程式碼

Array.prototype.reverse

/**
 * Array.prototype.reverse()
 * reverse()  方法將陣列中元素的位置顛倒,並返回該陣列。該方法會改變原陣列。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse
 * 方法顛倒陣列中元素的位置,並返回該陣列的引用。
 */
Array.prototype.myReverse = function(){
  if(!this.length) return this
  var len = this.length - 1
  var index = 0
  var mid = Math.floor(this.length / 2)
  while (index < mid) {
    var lastIndex = len-index
    var tem = this[index]
    var last = this[lastIndex]
    var indexEmpty = !(index in this)
    var lastIndexEmpty = !(lastIndex in this)

    if(lastIndexEmpty){
      delete this[index]
    }else{
      this[index] = last
    }
    if(indexEmpty){
      delete this[lastIndex]
    }else{
      this[len-index] = tem
    }
    index++
  }
  return this
}
var arr1 = [1,2,,3,,4,,5]
var arr2 = [1,2,,3,,4,,5]
arr1.myReverse()
console.log(arr1) //[5, empty, 4, empty, 3, empty, 2, 1]
arr2.reverse()
console.log(arr2) //[5, empty, 4, empty, 3, empty, 2, 1]
複製程式碼

Array.prototype.sort

/**
 * sort() 方法用原地演算法對陣列的元素進行排序,並返回陣列。排序演算法現在是穩定的。預設排序順序是根據字串Unicode碼點。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
 * compareFunction 可選
 * 用來指定按某種順序進行排列的函式。如果省略,元素按照轉換為的字串的各個字元的Unicode位點進行排序。
  * firstEl
  * 第一個用於比較的元素。
  * secondEl
  * 第二個用於比較的元素。
 */
/**
 * 快排
 * @param {*} arr 待排序陣列
 * @param {*} low 起點
 * @param {*} high 終點
 * @param {*} cb 比較函式
 */
function quickSort(arr,low,high,cb) {
  if(low<high){
    var mid = partition(arr,low,high,cb)
    quickSort(arr,low,mid-1,cb)
    quickSort(arr,mid+1,high,cb)
  }
  return arr
}
/**
 * 劃分函式 
 */
function partition(arr,low,high,cb) {
  var poivt = arr[low]
  while (low<high) {
    while (low<high && cb(arr[high],poivt) >= 0 ) {
      high--
    }
    arr[low] = arr[high]
    while (low<high && cb(arr[low],poivt) <= 0 ) {
      low++
    }
    arr[high] = arr[low]
  }
  arr[low] = poivt
  return low
}
Array.prototype.mySort = function(cb) {
  return quickSort(this,0,this.length-1,cb)
}


var arr1 = [3,5,5,-1,65,6,41,2,51,11,52,8]
var arr2 = [3,5,5,-1,65,6,41,2,51,11,52,8]
function fcb(a,b) {
  return a - b
}
console.log(arr1.mySort(fcb)) //[-1, 2, 3, 5, 5, 6, 8, 11, 41, 51, 52, 65]
console.log(arr2.sort(fcb)) //[-1, 2, 3, 5, 5, 6, 8, 11, 41, 51, 52, 65]
複製程式碼

Array.prototype.indexOf

/**
 * indexOf() 方法返回在陣列中可以找到一個給定元素的第一個索引,如果不存在,則返回-1。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
 * searchElement
  * 要查詢的元素
 * fromIndex
  * 開始查詢的位置。如果該索引值大於或等於陣列長度,意味著不會在陣列裡查詢,返回-1。
  * 如果引數中提供的索引值是一個負值,則將其作為陣列末尾的一個抵消,
  * 即-1表示從最後一個元素開始查詢,-2表示從倒數第二個元素開始查詢 ,以此類推。
  * 注意:
  * 如果引數中提供的索引值是一個負值,並不改變其查詢順序,
  * 查詢順序仍然是從前向後查詢陣列。如果抵消後的索引值仍小於0,則整個陣列都將會被查詢。其預設值為0.
 */
Array.prototype.myIndexOf = function(search,fromIndex){
  fromIndex = fromIndex ? typeof fromIndex === 'number' ? fromIndex 
                : typeof fromIndex === 'string' ? (fromIndex-=0) && fromIndex === fromIndex ? fromIndex 
                : 0 : 0 : 0
  var index = -1
  var len = this.length
  var i = fromIndex < 0 ? len + fromIndex : fromIndex
  while (i < len) {
    if(search == this[i]){
      index = i
      break
    }
    i++
  }
  return index
}
console.log(arr1.myIndexOf(5,{}) == arr1.indexOf(5,{})) //true
console.log(arr1.myIndexOf(5,[]) == arr1.indexOf(5,[])) //true
console.log(arr1.myIndexOf(5,[1]) == arr1.indexOf(5,[1])) //true
console.log(arr1.myIndexOf(5,'1') == arr1.indexOf(5,'1')) //true
console.log(arr1.myIndexOf(5,'1e') == arr1.indexOf(5,'1e')) //true
console.log(arr1.myIndexOf(5,true) == arr1.indexOf(5,true)) //true
console.log(arr1.myIndexOf(5,NaN) == arr1.indexOf(5,NaN)) //true
console.log(arr1.myIndexOf(5,-1) == arr1.indexOf(5,-1)) //true
console.log(arr1.myIndexOf(5,-5) == arr1.indexOf(5,-5)) //true
複製程式碼

Array.prototype.lastIndexOf

/**
 * lastIndexOf() 方法返回在陣列中可以找到一個給定元素的第一個索引,如果不存在,則返回-1。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf
 * searchElement
  * 要查詢的元素
 * fromIndex
  * 從此位置開始逆向查詢。預設為陣列的長度減 1,即整個陣列都被查詢。
  * 如果該值大於或等於陣列的長度,則整個陣列會被查詢。
  * 如果為負值,將其視為從陣列末尾向前的偏移。
  * 即使該值為負,陣列仍然會被從後向前查詢。
  * 如果該值為負時,其絕對值大於陣列長度,則方法返回 -1,
  * 即陣列不會被查詢。
 */
Array.prototype.myLastIndexOf = function(search,fromIndex){
  fromIndex = fromIndex ? typeof fromIndex === 'number' ? fromIndex 
              : (fromIndex-=0) && fromIndex === fromIndex ? fromIndex 
              : 0 
              : 0
  var index = -1
  var i = fromIndex < 0 ? fromIndex + this.length > 0 ? fromIndex + this.length : 0 : fromIndex > this.length ? this.length : fromIndex
  while (i > 0) {
    if(search == this[i]){
      index = i
      break
    }
    i--
  }
  return index
}
console.log(arr1.myLastIndexOf(5,{}) == arr1.lastIndexOf(5,{})) //true
console.log(arr1.myLastIndexOf(5,[]) == arr1.lastIndexOf(5,[])) //true
console.log(arr1.myLastIndexOf(5,[1]) == arr1.lastIndexOf(5,[1])) //true
console.log(arr1.myLastIndexOf(5,'1') == arr1.lastIndexOf(5,'1')) //true
console.log(arr1.myLastIndexOf(5,'1e') == arr1.lastIndexOf(5,'1e')) //true
console.log(arr1.myLastIndexOf(5,true) == arr1.lastIndexOf(5,true)) //true
console.log(arr1.myLastIndexOf(5,NaN) == arr1.lastIndexOf(5,NaN)) //true
console.log(arr1.myLastIndexOf(5,-1) == arr1.lastIndexOf(5,-1)) //true
console.log(arr1.myLastIndexOf(5,-5) == arr1.lastIndexOf(5,-5)) //true
複製程式碼

Array.prototype.from

/**
 * Array.from(arrayLike[, mapFn[, thisArg]]) 從一個類似陣列或可迭代物件中建立一個新的陣列例項。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/from
 * arrayLike
  * 想要轉換成陣列的偽陣列物件或可迭代物件。
 * mapFn (可選引數)
  * 如果指定了該引數,新陣列中的每個元素會執行該回撥函式。
 * thisArg (可選引數)
  * 可選引數,執行回撥函式 mapFn 時 this 物件。  
*/
Array.prototype.myFrom = function(arrayLike,mapFn,context) {
  context = context || window
  mapFn = mapFn || function(item){return item}
  var arr = []
  if(arrayLike.forEach){
    arrayLike.forEach((value)=>{
      arr.push(mapFn.call(context,value))
    })
  }else{
    var length = arrayLike.length
    var i = 0
    while (i<length) {
      arr.push(mapFn.call(context,arrayLike[i]))
      i++
    }
  }
  return arr
}
console.log(Array.prototype.myFrom(arrLike))
console.log(Array.prototype.myFrom(set))
console.log(Array.prototype.myFrom(map))
複製程式碼

Array.prototype.of

/**
 * Array.of(element0[, element1[, ...[, elementN]]]) 方法建立一個具有可變數量引數的新陣列例項,而不考慮引數的數量或型別。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/of
 * elementN
  * 任意個引數,將按順序成為返回陣列中的元素。  
*/
Array.prototype.myOf = function() {
  var len = arguments.length
  var arr =[]
  arr.length = len
  var i = 0
  while (i < len) {
    arr[i] = arguments[i]
    i++
  }
  return arr
  // return Array.prototype.mySlice.call(arguments)
  // return Array.prototype.myFrom.call(null,arguments)
}
console.log(Array.prototype.myOf(1,2,3))
console.log(Array.prototype.myOf(undefined))
console.log(Array.prototype.myOf(1))
複製程式碼

Array.prototype.copyWithin

/**
 * Array.copyWithin(target[, start[, end]]) 方法淺複製陣列的一部分到同一陣列中的另一個位置,並返回它,而不修改其大小。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin
 * target
  * 0 為基底的索引,複製序列到該位置。如果是負數,target 將從末尾開始計算。
  * 如果 target 大於等於 arr.length,將會不發生拷貝。如果 target 在 start 之後,複製的序列將被修改以符合 arr.length。
 * start
  * 0 為基底的索引,開始複製元素的起始位置。如果是負數,start 將從末尾開始計算。
  * 如果 start 被忽略,copyWithin 將會從0開始複製。
 * end
  * 0 為基底的索引,開始複製元素的結束位置。copyWithin 將會拷貝到該位置,但不包括 end 這個位置的元素。如果是負數, end 將從末尾開始計算。
  * 如果 end 被忽略,copyWithin 方法將會一直複製至陣列結尾(預設為 arr.length)。  
*/
Array.prototype.myCopyWithin = function(target,start,end) {
  var len = this.length
  target = target < 0 ? Math.abs(target) > len ? len : len + target : target > len ? len : target
  start = typeof start === 'number' ? start < 0 ? Math.abs(start) > len ? len : len + start : start > len ? len : start : 0
  end = typeof end === 'number' ? end < 0 ? Math.abs(end) > len ? len : len + end : end > len ? len : end : len
  var oTarget = target
  var offset = end - start
  var arr = Array.prototype.mySlice.call(this)
  while (target < len && (target-oTarget) < offset && start < end) {
    if(!this[start])break
    this[target] = arr[start]
    start++
    target++
  }
  return this
}
console.log([1, 2, 3, 4, 5].myCopyWithin(-2)); // [1, 2, 3, 1, 2]
console.log([1, 2, 3, 4, 5].copyWithin(-2)); // [1, 2, 3, 1, 2]
console.log([1, 2, 3, 4, 5].myCopyWithin(0, 3)); // [4, 5, 3, 4, 5]
console.log([1, 2, 3, 4, 5].copyWithin(0, 3)); // [4, 5, 3, 4, 5]
console.log([1, 2, 3, 4, 5].myCopyWithin(0, 3, 4));// [4, 2, 3, 4, 2]
console.log([1, 2, 3, 4, 5].copyWithin(0, 3, 4));// [4, 5, 3, 4, 5]
console.log([1, 2, 3, 4, 5].myCopyWithin(-2, -3, -1)); // [1, 2, 3, 3, 4]
console.log([1, 2, 3, 4, 5].copyWithin(-2, -3, -1)); // [1, 2, 3, 3, 4]
console.log([1, 2, 3, 4, 5].myCopyWithin(3, 2, 4)); // [1, 2, 3, 3, 4]
console.log([1, 2, 3, 4, 5].copyWithin(3, 2, 4)); // [1, 2, 3, 3, 4]
console.log([].myCopyWithin.call({length: 5, 3: 1}, 0, 3)); // {0: 1, 3: 1, length: 5}
console.log([].copyWithin.call({length: 5, 3: 1}, 0, 3)); // {0: 1, 3: 1, length: 5}
console.log([].myCopyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4));// Int32Array [4, 2, 3, 4, 5]
console.log([].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4));// Int32Array [4, 2, 3, 4, 5]
複製程式碼

Array.prototype.fill

/**
 * Array.fill(callback[, thisArg]) 方法用一個固定值填充一個陣列中從起始索引到終止索引內的全部元素。不包括終止索引。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/fill
 * value
  * 用來填充陣列元素的值。
 * start 可選
  * 起始索引,預設值為0。
 * end 可選
  * 終止索引,預設值為 this.length。
*/
Array.prototype.myFill = function(value,start,end) {
  var len = this.length
  start = typeof start === 'number' ? start < 0 ? Math.abs(start) > len ? len : len + start : start > len ? len : start : 0
  end = typeof end === 'number' ? end < 0 ? Math.abs(end) > len ? len : len + end : end > len ? len : end : len
  while (start < end) {
    this[start] = value
    start++
  }
  return this
}
console.log([1, 2, 3].myFill(4))               // [4, 4, 4]
console.log([1, 2, 3].myFill(4, 1))            // [1, 4, 4]
console.log([1, 2, 3].myFill(4, 1, 2))         // [1, 4, 3]
console.log([1, 2, 3].myFill(4, 1, 1))         // [1, 2, 3]
console.log([1, 2, 3].myFill(4, 3, 3))         // [1, 2, 3]
console.log([1, 2, 3].myFill(4, -3, -2))       // [4, 2, 3]
console.log([1, 2, 3].myFill(4, NaN, NaN))     // [1, 2, 3]
console.log([1, 2, 3].myFill(4, 3, 5))         // [1, 2, 3]
console.log(Array(3).myFill(4))                // [4, 4, 4]
console.log(Array.prototype.myFill.call({ length: 3 }, 4))  // {0: 4, 1: 4, 2: 4, length: 3}
複製程式碼

Array.prototype.includes

/**
 * Array.prototype.includes(valueToFind[, fromIndex])方法用來判斷一個陣列是否包含一個指定的值,根據情況,如果包含則返回 true,否則返回false。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
 * valueToFind
  * 需要查詢的元素值。
 * fromIndex 可選
  * 從fromIndex 索引處開始查詢 valueToFind。預設為 0。
  * 如果為負值,則按升序從 array.length + fromIndex 的索引開始搜 (即使從末尾開始往前跳 fromIndex 的絕對值個索引,然後往後搜尋)。
*/
Array.prototype.myIncludes = function(valueToFind,findIndex) {
  var len = this.length
  findIndex = typeof findIndex === 'number' ? findIndex < 0 ? Math.abs(findIndex) > len ? len : len + findIndex : findIndex > len ? len : findIndex : 0
  while (findIndex < len) {
    var now = this[findIndex]
    if(valueToFind === now)return true
    if(valueToFind !== valueToFind && now !== now)return true
    findIndex++
  }
  return false
}
console.log([1, 2, 3].myIncludes(2))     // true
console.log([1, 2, 3].myIncludes(4))     // false
console.log([1, 2, 3].myIncludes(3, 3))  // false
console.log([1, 2, 3].myIncludes(3, -1)) // true
console.log([1, 2, NaN].myIncludes(NaN)) // true
複製程式碼

Array.prototype.keys

/**
 * Array.prototype.keys()方法返回一個包含陣列中每個索引鍵的Array Iterator物件。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/keys
*/
Array.prototype.myKeys = function() {
  if(!typeof this === 'object')return 
  var arr = null
  var length = this.length
  if(!length){
    arr = []
    for (const key in this) {
      if (this.hasOwnProperty(key)) {
        arr.push(key)
      }
    }
  }
  var len = this.length || arr.length
  var nextIndex = 0
  return {
    //[Symbol.iterator]需要在物件新增此屬性,才是一個可被 for...of 遍歷的物件
    [Symbol.iterator]: function(){
      return {
        next:function(){
          return nextIndex < len ? {value: length ? nextIndex++ : arr[nextIndex++], done:false} : {done:true}
        }
      }
    }
  }
}
var a = ["a", "b", "c"].myKeys()
var b = Array.prototype.myKeys.call({0:1,1:2,length:2})
var c = Array.prototype.myKeys.call({a:1,b:2})
for (const value of a) {
  console.log(value) // 0 1 2
}
for (const value of b) {
  console.log(value) // 0 1
}
for (const value of c) {
  console.log(value) // a b
}
複製程式碼

Array.prototype.values

/**
 * Array.prototype.values()方法返回一個新的 Array Iterator 物件,該物件包含陣列每個索引的值。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/values
*/
Array.prototype.myValues = function() {
  if(!typeof this === 'object')return 
  var arr = this
  if(!this.length){
    arr = []
    for (const key in this) {
      if (this.hasOwnProperty(key)) {
        arr.push(this[key])
      }
    }
  }
  var len = this.length || arr.length
  var nextIndex = 0
  return {
    //[Symbol.iterator]需要在物件新增此屬性,才是一個可被 for...of 遍歷的物件
    [Symbol.iterator]: function(){
      return {
        next:function(){
          return nextIndex < len ? {value: arr[nextIndex++], done:false} : {done:true}
        }
      }
    }
  }
}
var a = ["a", 'b', "c"].myValues()
var b = Array.prototype.myValues.call({0:1,1:2,length:2})
var c = Array.prototype.myValues.call({a:1,b:2})
for (const value of a) {
  console.log(value) // a b c
}
for (const value of b) {
  console.log(value) // 1 2
}
for (const value of c) {
  console.log(value) // 1 2
}
複製程式碼

Array.prototype.entries

/**
 * Array.prototype.entries()方法返回一個新的Array Iterator物件,該物件包含陣列中每個索引的鍵/值對。
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/entries
*/
Array.prototype.myEntries = function() {
  if(!typeof this === 'object')return 
  var arr = this
  var len = this.length || arr.length
  var nextIndex = 0
  return {
    //[Symbol.iterator]需要在物件新增此屬性,才是一個可被 for...of 遍歷的物件
    [Symbol.iterator]: function(){
      return {
        next:function(){
          return nextIndex < len ? {value:[nextIndex,arr[nextIndex++]], done:false} : {done:true}
        }
      }
    }
  }
}
var a = ["a", 'b', "c"].myEntries()
var b = Array.prototype.myEntries.call({0:1,1:2,length:2})
for (const value of a) {
  console.log(value) // [0,"a"]  [0, "b"]  [0, "c"]
}
for (const value of b) {
  console.log(value) // [0, 1]  [0, 2]
}
複製程式碼

相關文章