最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 对 js 数组常用函数的手动实现

    正文概述 掘金(对半)   2021-05-02   618

    在JavaScript的数组类型上有各种各样的方便快捷的操作方法,如果对各个方法能够灵活的应用,对于开发来说,将能很大的提升工作效率。

    注意: 以下方法主要为了熟悉数组自带的方法,属于模拟实现,不表示底层的实现方式。

    数组的上常用的方法大概有:

    • 改变原数组方法: sort,pop,push,shift,unshift,reverse,splice,fill
    • 不改变原数组方法: forEach,map,filter,find,findIndex,every,some,reduce,reduceRight,join,concat,includes,keys,values,indexOf,lastIndexOf,slice,flat,flatMap

    改变原数组的方法

    #sort

    sort 方法是用来对数组进行排序一个内置方法,采用的是进行原地排序,所以会改变原数组,而现代浏览器有的是用归并排序,有的是用快速排序,还有的结合了插入排序。V8引擎采用的是插入和快排混合。这里就不搞那么复杂了,就用三切分快速排序来写了。

    参数

    • compareFunction 可选。用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的各个字符的Unicode位点进行排序。
      • firstEl:第一个用于比较的元素。
      • secondEl:第二个用于比较的元素。

    返回值

    • 排序后的数组。请注意,数组已原地排序,并且不进行复制。

    sort 方法的参数是一个 compareFunction 函数,compareFunction 函数的参数是要比较的a、b两个值。该函数返回的值三种情况:

    • 小于0:a 小于 b
    • 等于0:a 等于 b
    • 大于0:a 大于 b

    代码:

    Array.prototype.$sort = function(callback) {
      // 边界处理
      if (typeof callback !== 'function') {
        throw new TypeError('The comparison function must be either a function')
      }
      let _this = this
      let l = 0;
      let r = _this.length - 1
    
      // 三切分快排
      function quickSort(l, r) {
        if (l >= r) return
        let i = l + 1
        let lf = l
        let ri = r
        let base = _this[l]
    
        while(i <= ri) {
          if (callback(base, _this[i]) < 0) {
            [_this[i], _this[ri--]] = [_this[ri], _this[i]]
          } else if (callback(base, _this[i]) > 0) {
            [_this[lf++], _this[i++]] = [_this[i], _this[lf]]
          } else {
            i++
          }
        }
    
        quickSort(l, lf - 1)
        quickSort(ri + 1, r)
      }
    
      quickSort(l, r)
      return _this
    }
    

    sort 方法还有一种情况就是参数可以不传,即 undefined,在原生 sort 中,如果没有传 callback,就会对数组的值进行字符串处理,然后再对字符串进行比较。这样上面代码可以再修改下:

    完整代码:

    Array.prototype.$sort = function(callback) {
      // 边界处理
      if (typeof callback !== 'function' && callback !== undefined) {
        throw new TypeError('The comparison function must be either a function or undefined')
      }
    
      // 如果callback为undefined,则采用默认方式,转字符串再比较
      if (callback === undefined) {
        callback = (a, b) => String(a) > String(b) ? 1 : -1
      }
      let _this = this
      let l = 0;
      let r = _this.length - 1
      
      // sort方法会先对数组内的undefined值进行提取,放在末尾,不进行比较排序
      while(l <= r) {
        if (_this[l] === undefined) {
          [_this[l], this[r--]] = [_this[r], _this[l]]
        } else {
          l++
        }
      }
    
      l = 0 // 重置l
    
      // 三切分快排
      function quickSort(l, r) {
        if (l >= r) return
        let i = l + 1
        let lf = l
        let ri = r
        let base = _this[l]
    
        while(i <= ri) {
          if (callback(base, _this[i]) < 0) {
            [_this[i], _this[ri--]] = [_this[ri], _this[i]]
          } else if (callback(base, _this[i]) > 0) {
            [_this[lf++], _this[i++]] = [_this[i], _this[lf]]
          } else {
            i++
          }
        }
    
        quickSort(l, lf - 1)
        quickSort(ri + 1, r)
      }
    
      quickSort(l, r)
    
      return _this
    }
    

    #pop

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

    返回值

    • 从数组中删除的元素(当数组为空时返回undefined)。

    代码:

    Array.prototype.$pop = function() {
      if (this.length === 0) return undefined
      let lastValue = this[this.length - 1]
      this.length--
      return lastValue
    }
    

    #push

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

    参数

    • elementN:被添加到数组末尾的元素。

    返回值

    • 当调用该方法时,新的 length 属性值将被返回。

    代码:

    Array.prototype.$push = function(...args) {
      if (args.length === 0) return 0
    
      for (let i = 0; i < args.length; i++) {
        this[this.length++] = args[i]
      }
    
      return this.length
    }
    

    #shift

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

    返回值

    • 从数组中删除的元素; 如果数组为空则返回undefined 。

    代码:

    Array.prototype.$shift = function() {
      let firstValue = this[0]
      for (let i = 0; i < this.length - 1; i++) {
        this[i] = this[i + 1]
      }
      this.length--
      return firstValue
    }
    

    #unshift

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

    参数

    • elementN:要添加到数组开头的元素或多个元素。

    返回值

    • 当一个对象调用该方法时,返回其 length 属性值。

    代码:

    Array.prototype.$unshift = function(...args) {
      let len = args.length
    
      this.length += len
    
      // 整体右移 len 位
      for (let i = this.length - 1; i >= len; i--) {
        this[i] = this[i - len]
      }
    
      // 添加到头部
      for (let i = 0; i < len; i++) {
        this[i] = args[i]
      }
    
      return this.length
    }
    

    #splice

    splice 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。

    参数

    • start:指定修改的开始位置(从0计数)。如果超出了数组的长度,则从数组末尾开始添加内容;如果是负值,则表示从数组末位开始的第几位(从-1计数,这意味着-n是倒数第n个元素并且等价于array.length-n);如果负数的绝对值大于数组的长度,则表示开始位置为第0位。
    • deleteCount 可选。整数,表示要移除的数组元素的个数。
      • 如果 deleteCount 大于 start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。
      • 如果 deleteCount 被省略了,或者它的值大于等于array.length - start(也就是说,如果它大于或者等于start之后的所有元素的数量),那么start之后数组的所有元素都会被删除。
      • 如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。
    • item1, item2, ... 可选。要添加进数组的元素,从start 位置开始。如果不指定,则 splice() 将只删除数组元素。

    返回值

    • 由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。

    代码:

    Array.prototype.$splice = function (start, deleCount, ...args) {
      start |= 0
      if (start < 0) {
        start = this.length + start
      }
      
      delecount |= 0
    
      deleCount < 0 && (deleCount = 0)
      let addNum = args.length
    
      let changeLen = addNum - deleCount
      let deleteValues = new Array(deleCount)
      for (let i = 0; i < deleCount; i++) {
        deleteValues[i] = this[start + i]
      }
    
      // 新增的值比删除的多
      if (changeLen > 0) {
        this.length += changeLen
        // 从start开始右移changelen位
        for (let i = this.length - 1; i >= start + changeLen; i--) {
          this[i] = this[i - changeLen]
        }
      } else { // 删除比新增的多
        // changeLen为负数,左移
        for (let i = start + addNum; i < this.length - addNum; i++) {
          this[i] = this[i - changeLen]
        }
        this.length += changeLen
      }
      // 填充需要添加的元素
      for (let i = 0; i < addNum; i++) {
        this[i + start] = args[i]
      }
      return deleteValues
    }
    

    V8的js底层在实现数组是用了两种结构来实现:快数组(传统数组)和慢数组(散列表),对于pop、push、shift、unshift、splice这些能够更改数组长度的方法,在底层上的实现还需要考虑空间的利用率及性能问题,这涉及到对数组已分配的内存容量的扩容、收缩和快慢数组的转换。

    #reverse

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

    返回值

    • 颠倒后的数组。

    代码:

    Array.prototype.$reverse = function() {
      let l = 0
      let r = this.length - 1
    
      while(l <= r) {
        [this[l++], this[r--]] = [this[r], this[l]]
      }
      
      return this
    }
    

    #fill

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

    参数

    • value:用来填充数组元素的值。
    • start 可选。起始索引,默认值为0。
    • end 可选。终止索引,默认值为 this.length。

    返回值

    • 修改后的数组。

    代码:

    Array.prototype.$fill = function(val, start, end) {
      if (start === undefined) {
        start = 0
      }
      if (end === undefined) {
        end = this.length
      }
    
      start |= 0
      end |= 0
    
      if (start < 0) {
        start = this.length + start
      }
      if (end < 0) {
        end = this.length + end
      }
    
      if (start >= end) {
        return this
      }
      
      for (let i = start; i < end; i++) {
        this[i] = val
      }
      
      return this
    }
    

    不改变原数组的方法

    #forEach

    forEach 方法对数组的每个元素执行一次给定的函数。

    参数

    • callback:为数组中每个元素执行的函数,有三个参数
      • currValue: 当前操作的值
      • index: 可选。当前操作的索引
      • array: 可选。正则操作的数组
    • thisArg:可选。当执行回调函数 callback 时,用作 this 的值

    返回值

    • undfined

    代码:

    Array.prototype.$forEach = function(callback, thisArg) {
      let type = Object.prototype.toString.call(callback)
      if (type !== "[object Function]" && type !== "[object AsyncFunction]") {
        throw new TypeError(type + ' is not a function')
      }
      for (let i = 0; i < this.length; i++) {
        // forEach 原生方法对空缺的数组单元不进行任何操作
        // [1, empty, 3] -- empty 为空缺单元
        // Todo 暂时没有找到怎么判断数组内某个位置的空缺 
        callback.call(thisArg || window, this[i], i, this)
      }
    }
    

    #map

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

    参数

    • callback:生成新数组元素的函数,有三个参数
      • currValue: 当前操作的值
      • index: 可选。当前操作的索引
      • array: 可选。正则操作的数组
    • thisArg:可选。当执行回调函数 callback 时,用作 this 的值

    返回值

    • 一个由原数组每个元素执行回调函数的结果组成的新数组。

    代码:

    Array.prototype.$map = function(callback, thisArg) {
      if (typeof callback !== 'function') {
        throw new TypeError(callback + ' is not a function')
      }
      let newArray = new Array(this.length)
    
      for (let i = 0; i < this.length; i++) {
        newArray[i] = callback.call(thisArg || window, this[i], i, this)
      }
    
      return newArray
    }
    

    #filter

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

    参数

    • callback:用来测试数组的每个元素的函数。返回 true 表示该元素通过测试,保留该元素,false 则不保留,有三个参数
      • currValue: 当前操作的值
      • index: 可选。当前操作的索引
      • array: 可选。正则操作的数组
    • thisArg:可选。当执行回调函数 callback 时,用作 this 的值

    返回值

    • 一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。

    代码:

    Array.prototype.$filter = function(callback, thisArg) {
      if (typeof callback !== 'function') {
        throw new TypeError(callback + ' is not a function')
      }
    
      let newArray = new Array()
    
      for (let i = 0, j = 0; i < this.length; i++) {
        if (callback.call(thisArg || window, this[i], i, this)) {
          newArray[j++] = this[i]
        }
      }
    
      return newArray
    }
    

    #find

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

    参数

    • callback:在数组每一项上执行的函数,有三个参数
      • currValue: 当前操作的值
      • index: 可选。当前操作的索引
      • array: 可选。正则操作的数组
    • thisArg:可选。当执行回调函数 callback 时,用作 this 的值

    返回值

    • 数组中第一个满足所提供测试函数的元素的值,否则返回 undefined。

    代码:

    Array.prototype.$find = function(callback, thisArg) {
      if (typeof callback !== 'function') {
        throw new TypeError(callback + ' is not a function')
      }
    
      for (let i = 0; i < this.length; i++) {
        if (callback.call(thisArg || window, this[i], i, this)) {
          return this[i]
        }
      }
    
      return
    }
    

    #findIndex

    findIndex 方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。

    参数

    • callback:针对数组中的每个元素, 都会执行该回调函数,有三个参数
      • currValue: 当前操作的值
      • index: 可选。当前操作的索引
      • array: 可选。正则操作的数组
    • thisArg:可选。当执行回调函数 callback 时,用作 this 的值

    返回值

    • 数组中通过提供测试函数的第一个元素的索引。否则,返回-1

    代码:

    Array.prototype.$findIndex = function(callback, thisArg) {
      if (typeof callback !== 'function') {
        throw new TypeError(callback + ' is not a function')
      }
    
      for (let i = 0; i < this.length; i++) {
        if (callback.call(thisArg || window, this[i], i, this)) {
          return i
        }
      }
    
      return -1
    }
    

    #every

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

    注意: 若收到一个空数组,此方法在一切情况下都会返回 true。

    参数

    • callback:针对数组中的每个元素, 都会执行该回调函数,有三个参数
      • currValue: 当前操作的值
      • index: 可选。当前操作的索引
      • array: 可选。正则操作的数组
    • thisArg:可选。当执行回调函数 callback 时,用作 this 的值

    返回值

    • 如果回调函数的每一次返回都为 truthy 值,返回 true ,否则返回 false。

    代码:

    Array.prototype.$every = function(callback, thisArg) {
      if (typeof callback !== 'function') {
        throw new TypeError(callback + ' is not a function')
      }
    
      for (let i = 0 ; i < this.length; i++) {
        if (!callback.call(thisArg || window, this[i], i, this)) {
          return false
        }
      }
    
      return true
    }
    

    #some

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

    注意: 如果用一个空数组进行测试,在任何情况下它返回的都是false。

    参数

    • callback:针对数组中的每个元素, 都会执行该回调函数,有三个参数
      • currValue: 当前操作的值
      • index: 可选。当前操作的索引
      • array: 可选。正则操作的数组
    • thisArg:可选。当执行回调函数 callback 时,用作 this 的值

    返回值

    • 数组中有至少一个元素通过回调函数的测试就会返回true;所有元素都没有通过回调函数的测试返回值才会为false。

    代码:

    Array.prototype.$some = function(callback, thisArg) {
      if (typeof callback !== 'function') {
        throw new TypeError(callback + ' is not a function')
      }
    
      if (this.length === 0) {
        return false
      }
    
      for (let i = 0 ; i < this.length; i++) {
        if (callback.call(thisArg || window, this[i], i, this)) {
          return true
        }
      }
    
      return false
    }
    

    #reduce

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

    参数

    • callback: 执行数组中每个值 (如果没有提供 initialValue则第一个值除外)的函数,包含四个参数:
      • accumulator: 累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。
      • currentValue: 数组中正在处理的元素。
      • index: 可选。数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始。
      • array:可选。调用reduce()的数组
    • initialValue:可选。作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错

    注意: 如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。

    返回值

    • 函数累计处理的结果。

    代码:

    Array.prototype.$reduce = function(callback, initial) {
      if (typeof callback !== 'function') {
        throw new TypeError(callback + ' is not a function')
      }
      
      if (this.length === 0 && !initial) {
        throw new TypeError('Reduce of empty array with no initial value')
      }
    
      let prevVal = 0
    
      // 有初始值
      if (initial !== undefined) {
        prevVal = initial
    
        for (let i = 0; i < this.length; i++) {
          prevVal = callback(prevVal, this[i], i, this)
        }
      } else { // 没有初始值
        prevVal = this[0]
    
        for (let i = 1; i < this.length; i++) {
          prevVal = callback(prevVal, this[i], i, this)
        }
      }
    
      return prevVal
    }
    

    #reduceRight

    reduceRight 方法接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。

    参数

    • callback:一个回调函数,用于操作数组中的每个元素,它可接受四个参数:
      • accumulator累加器: 上一次调用回调函数时,回调函数返回的值。首次调用回调函数时,如果 initialValue 存在,累加器即为 initialValue,否则须为数组中的最后一个元素(详见下方 initialValue 处相关说明)。
      • currentValue当前元素:当前被处理的元素。
      • index可选。数组中当前被处理的元素的索引。
      • array可选。调用 reduceRight() 的数组。
    • initialValue可选。首次调用 callback 函数时,累加器 accumulator 的值。如果未提供该初始值,则将使用数组中的最后一个元素,并跳过该元素。如果不给出初始值,则需保证数组不为空。否则,在空数组上调用 reduce 或 reduceRight 且未提供初始值(例如 [].reduce( (acc, cur, idx, arr) => {} ) )的话,会导致类型错误 TypeError: reduce of empty array with no initial value。

    返回值

    • 执行之后的返回值。

    代码:

    Array.prototype.$reduceRight = function(callback, initial) {
      if (typeof callback !== 'function') {
        throw new TypeError(callback + ' is not a function')
      }
    
      if (this.length === 0 && !initial) {
        throw new TypeError('Reduce of empty array with no initial value')
      }
    
      let prevVal = 0
    
      // 有初始值
      if (initial !== undefined) {
        prevVal = initial
    
        for (let i = this.length - 1; i >= 0; i--) {
          prevVal = callback(prevVal, this[i], i, this)
        }
      } else { // 没有初始值
        prevVal = this[this.length - 1]
    
        for (let i = this.length - 2; i >= 0; i--) {
          prevVal = callback(prevVal, this[i], i, this)
        }
      }
    
      return prevVal
    }
    

    #join

    join 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。

    参数

    • separator 可选。指定一个字符串来分隔数组的每个元素。如果需要,将分隔符转换为字符串。如果缺省该值,数组元素用逗号(,)分隔。如果separator是空字符串(""),则所有元素之间都没有任何字符。

    返回值

    • 一个所有数组元素连接的字符串。如果 arr.length 为0,则返回空字符串。

    代码:

    Array.prototype.$join = function(separator) {
      separator = separator === undefined ? ',' : separator
      
      if (this.length === 0) {
        return ''
      }
    
      let str = this[0]
    
      for (let i = 1; i < this.length; i++) {
        str += separator + this[i]
      }
    
      return str
    }
    

    #concat

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

    参数

    • valueN可选。数组和/或值,将被合并到一个新的数组中。如果省略了所有 valueN 参数,则 concat 会返回调用此方法的现存数组的一个浅拷贝。

    返回值

    • 新的 Array 实例。

    代码:

    Array.prototype.$concat = function(...args) {
    
      let newArray = new Array(this.length)
    
      for (let i = 0; i < this.length; i++) {
        newArray[i] = this[i]
      }
    
      let cur = null
      for (let i = 0, k = this.length; i < args.length; i++) {
        cur = args[i]
        if (Array.isArray(cur)) {
          for (let j = 0; j < cur.length; j++) {
            newArray[k++] = cur[j]
          }
        } else {
          newArray[k++] = cur
        }
      }
    
      return newArray
    }
    

    #inludes

    inludes 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。

    参数

    • valueToFind:需要查找的元素值。
      • Note: 使用 includes()比较字符串和字符时是区分大小写。
    • fromIndex 可选。从fromIndex 索引处开始查找 valueToFind。如果为负值,则按升序从 array.length + fromIndex 的索引开始搜 (即使从末尾开始往前跳 fromIndex 的绝对值个索引,然后往后搜寻)。默认为 0。

    返回值

    • 返回一个布尔值 Boolean ,如果在数组中找到了(如果传入了 fromIndex ,表示在 fromIndex 指定的索引范围中找到了)则返回 true 。

    代码:

    Array.prototype.$includes = function(value, findIndex) {
      findIndex |= 0
      if (findIndex < 0) {
        findIndex = this.length + findIndex
      }
    
      for (let i = findIndex; i < this.length; i++) {
        // NaN会被认为是相等的
        if (this[i] === value || (typeof this[i] === 'number' && typeof value === 'number' && isNaN(this[i]) && isNaN(value))) {
          return true
        }
      }
    
      return false
    }
    

    #keys

    keys 方法返回一个包含数组中每个索引键的Array Iterator对象。

    返回值

    • 一个新的 Array 迭代器对象。

    代码:

    Array.prototype.$keys = function() {
      let newArray = new Array(this.length)
    
      for (let i = 0; i < this.length; i++) {
        newArray[i] = i
      }
    
      return newArray[Symbol.iterator]()
    }
    

    #values

    values 方法返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值。

    返回值

    • 一个新的 Array 迭代器对象。

    代码:

    Array.prototype.$values = function() {
      return this[Symbol.iterator]()
    }
    

    #indexOf

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

    参数

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

    返回值

    • 首个被找到的元素在数组中的索引位置; 若没有找到则返回 -1

    代码:

    Array.prototype.$indexOf = function(value, fromIndex) {
      fromIndex |= 0
    
      if (fromIndex < 0) {
        fromIndex = this.length + fromIndex
      }
    
      for (let i = fromIndex; i < this.length; i++) {
        if (this[i] === value) {
          return i
        }
      }
    
      return -1
    }
    

    #lastIndexOf

    lastIndexOf 方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从 fromIndex 处开始。

    参数

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

    返回值

    • 数组中该元素最后一次出现的索引,如未找到返回-1。

    代码:

    Array.prototype.$lastIndexOf = function(value, fromIndex) {
      fromIndex |= 0
    
      if (fromIndex < 0) {
        fromIndex = this.length + fromIndex
      }
    
      for (let i = fromIndex; i >= 0; i--) {
        if (this[i] === value) {
          return i
        }
      }
    
      return -1
    }
    

    #slice

    slice 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。

    参数

    • begin 可选。提取起始处的索引(从 0 开始),从该索引开始提取原数组元素。
      • 如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2) 表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。
      • 如果省略 begin,则 slice 从索引 0 开始。
      • 如果 begin 超出原数组的索引范围,则会返回空数组。
    • end 可选。提取终止处的索引(从 0 开始),在该索引处结束提取原数组元素。slice 会提取原数组中索引从 begin 到 end 的所有元素(包含 begin,但不包含 end)。
      • slice(1,4) 会提取原数组中从第二个元素开始一直到第四个元素的所有元素 (索引为 1, 2, 3的元素)。
      • 如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。 slice(-2,-1) 表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。
      • 如果 end 被省略,则 slice 会一直提取到原数组末尾。
      • 如果 end 大于数组的长度,slice 也会一直提取到原数组末尾。

    返回值

    • 一个含有被提取元素的新数组。

    代码:

    Array.prototype.$slice = function(start, end) {
      start |= 0
      if (end === undefined) {
        end = this.length
      } else {
        end |= 0
      }
    
      if (start < 0) {
        start = this.length + start
      }
      if (end < 0) {
        end = this.length + end
      }
    
      if (start >= end) {
        return []
      }
      let newArray = new Array(end - start)
    
      for (let i = start, j = 0; i < end; i++) {
        newArray[j++] = this[i]
      }
    
      return newArray
    }
    

    #flat

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

    参数

    • depth 可选。指定要提取嵌套数组的结构深度,默认值为 1。

    返回值

    • 一个包含将数组与子数组中所有元素的新数组。

    代码:

    Array.prototype.$flat = function (depth) {
      if (depth === undefined) {
        depth = 1
      } else {
        depth |= 0
      }
    
      let res = []
      function flatten(arr, deep) {
        if (deep >= depth) return [...arr]
        let hasArray = false
        res = []
        for (let i = 0; i < arr.length; i++) {
          if (Array.isArray(arr[i])) {
            hasArray = true
            res.$push(...arr[i]) // 用的是上面的方法
          } else {
            res.$push(arr[i])
          }
        }
    
        if (hasArray) {
          return flatten(res, deep + 1)
        }
        return res
      }
    
      return flatten(this, 0)
    }
    

    #flatMap

    flatMap 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 连着深度值为1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。

    参数

    • callback:可以生成一个新数组中的元素的函数,可以传入三个参数:
      • currentValue:当前正在数组中处理的元素
      • index可选。数组中正在处理的当前元素的索引。
      • array可选。被调用的 map 数组
    • thisArg可选。执行 callback 函数时 使用的this 值。

    返回值

    • 一个新的数组,其中每个元素都是回调函数的结果,并且结构深度 depth 值为1。

    代码:

    Array.prototype.$flatMap = function(callback, thisArg) {
      if (typeof callback !== 'function') {
        throw new TypeError('flatMap mapper function is not callable')
      }
    
      let newArray = new Array()
      let res = null
    
      for (let i = 0; i < this.length; i++) {
        res = callback.call(thisArg || window, this[i], i, this)
        if (Array.isArray(res)) {
          newArray.$push(...res)
        } else {
          newArray.push(res)
        }
      }
    
      return newArray
    }
    

    起源地下载网 » 对 js 数组常用函数的手动实现

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元