JavaScript实现数组方法

89 阅读4分钟

一、Array.flat(depth)

  • depth:可选参数,指定展平的深度,默认情况下,深度为 1
Array.prototype.myFlat = function(dep) {
  if(dep === undefined) dep = 1
  if(!Array.isArray(this) || dep < 1) return this

  return this.reduce((prev, curt) => {;
    if(Array.isArray(curt)) {
      return prev.concat(curt.myFlat(dep-1))
    } else {
      return prev.concat(curt)
    }
  },[])
}
let arr = [1, [2, [3, 4, 5]]] 
console.log(arr.myFlat())   // [ 1, 2, [ 3, 4, 5 ] ]
console.log(arr.myFlat(2))  // [ 1, 2, 3, 4, 5 ]

二、Array.prototype.push()

  • push:方法将指定的元素添加到数组的末尾,并返回新的数组长度
Array.prototype.myPush = function() {
  for(let i = 0; i < arguments.length; i++) {
    this[this.length] = arguments[i]
  }
  return this.length
}
let arr = []
console.log(arr.myPush(1,2,3))  // 3
console.log(arr)              // [ 1, 2, 3 ]

三、Array.prototype.filter()

  • filter():方法创建给定数组一部分的浅拷贝,其包含通过所提供函数实现的测试的所有元素。
Array.prototype.myFilter= function(fn) {
  if(typeof fn !== 'function') return
  let res = []
  for(let i = 0; i < this.length; i++) {
    fn(this[i]) && res.push(this[i])
  }
  return res
}
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present']
const result = words.myFilter((word) => word.length > 6)
console.log(result) // [ 'exuberant', 'destruction', 'present' ]

四、Array.prototype.map()

  • map():方法创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成
Array.prototype.myFilter= function(fn) {
  if(typeof fn !== 'function') return
  let res = []
  for(let i = 0; i < this.length; i++) {
    res.push(fn(this[i]))
  }
  return res
}
const arr = [1, 4, 9, 16]
console.log(arr.map((x) => x * 2)) // [ 2, 8, 18, 32 ]

五、Array.prototype.every()

  • every():方法测试一个数组内的所有元素是否都能通过指定函数的测试。它返回一个布尔值
Array.prototype.myEvery = function(fn) {
  if(typeof fn !== 'function') return
  for(let i = 0; i < this.length; i++) {
    if(!fn(this[i])) return false
  }
  return true
}

let arr = [11, 33, 55, 21, 35, 12]
console.log(arr.myEvery(item => item > 10)) // true
console.log(arr.myEvery(item => item > 20)) // false

六、Array.prototype.find()

  • find():方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined
Array.prototype.myFind = function(fn) {
  if(typeof fn !== 'function') return
  for(let i = 0; i < this.length; i++) {
    if(fn(this[i])) return this[i]
  }
}
let arr = [1, 3, 6, 9, 12]
console.log(arr.myFind((item =>item > 6)))  // 9
console.log(arr.myFind((item =>item > 15))) // undefined

七、Array.prototype.reduce()

  • reduce():方法对数组中的每个元素按序执行一个提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值
Array.prototype.myReduce = function(fn, initalValue) {
  if(typeof fn !== 'function') return
  //如果没有传递initialValue,我们将使用数组的第一项作为initialValue的值
  let hasInitalValue = initalValue !== undefined
  let value = hasInitalValue ? initalValue : this[0]
  //如果没有传递initialValue,则索引从1开始,否则从0开始
  for(let i = hasInitalValue ? 0 : 1; i < this.length; i++) {
    value = fn(value, this[i])
  }
  return value
}

let arr = [1, 2, 3, 4, 5, 6]
let sum = arr.myReduce(function (accumulator, currentValue) {
  return accumulator + currentValue
}, 0)
console.log(sum) //21

八、Array.prototype.some()

  • some():方法测试数组中是否至少有一个元素通过了由提供的函数实现的测试。如果在数组中找到一个元素使得提供的函数返回 true,则返回 true;否则返回 false
Array.prototype.mySome = function(fn) {
  if(typeof fn !== 'function') return
  for(let i = 0; i < this.length; i++) {
    if(fn(this[i])) return true
  }
  return false
}
let arr = [1, 3, 5, 7, 90]
console.log(arr.mySome(item => item > 10))  // true

九、数组去重

1. 利用Set()+Array.from()

  • Set对象:是值的集合,你可以按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即Set中的元素是唯一的
  • Array.from() 方法:对一个类似数组可迭代对象创建一个新的,浅拷贝的数组实例
  • NaNundefined类型去重也是有效的,是因为NaNundefined都可以被存储在Set中, NaN之间被视为相同的值(尽管在js中:NaN !== NaN)
const arr = [1, 2, 2, 'abc', 'abc', true, true, false, false, undefined, undefined, NaN, NaN]
const result = Array.from(new Set(arr))
console.log(result) // [ 1, 2, 'abc', true, false, undefined, NaN ]

2. 利用两层循环+数组的splice方法

  • 通过两层循环对数组元素进行逐一比较,然后通过splice方法来删除重复的元素
  • 无法对NaN进行去重的,因为进行比较时NaN !== NaN
function removeDuplicate(arr) {
  let len = arr.length
  for(let i = 0; i < len - 1; i++) {
    for(let j = i + 1; j < len; j++) {
      if(arr[i] === arr[j]) {
        arr.splice(j, 1)
        j--
        len--
      }
    }
  }
  return arr
}
const arr = [1, 2, 2, 'abc', 'abc', true, true, false, false, undefined, undefined, NaN, NaN]
console.log(removeDuplicate(arr)) // [ 1, 2, 'abc', true, false, undefined, NaN, NaN ]

3. 利用数组的indexOf方法

  • 新建一个空数组,遍历需要去重的数组,将数组元素存入新数组中,存放前判断数组中是否已经含有当前元素,没有则存入
  • 无法对NaN去重
function removeDuplicate(arr) {
  let newArr = []
  arr.forEach(item => {
    if(newArr.indexOf(item) === -1) {
      newArr.push(item)
    }
  })
  return newArr
}
const arr = [1, 2, 2, 'abc', 'abc', true, true, false, false, undefined, undefined, NaN, NaN]
console.log(removeDuplicate(arr)) // [ 1, 2, 'abc', true, false, undefined, NaN, NaN ]

4. 利用数组的includes方法

  • 用includes方法来判断是否包含重复元素
  • includes能够检测到数组中包含NaN,其涉及到includes底层的实现,在进行判断是否包含某元素时会调用sameValueZero方法进行比较,如果为NaN,则会使用isNaN()进行转化
function removeDuplicate(arr) {
  let newArr = []
  arr.forEach(item => {
    if(!newArr.includes(item)) {
      newArr.push(item)
    }
  })
  return newArr
}
const arr = [1, 2, 2, 'abc', 'abc', true, true, false, false, undefined, undefined, NaN, NaN]
console.log(removeDuplicate(arr)) // [ 1, 2, 'abc', true, false, undefined, NaN ]

5. 利用数组的filter()+indexOf()

  • 输出结果中不包含NaN,是因为indexOf()无法对NaN进行判断,即arr.indexOf(item) === index返回结果为false
function removeDuplicate(arr) {
  return arr.filter((item, index) => {
    return arr.indexOf(item) === index
  })
}
const arr = [1, 2, 2, 'abc', 'abc', true, true, false, false, undefined, undefined, NaN, NaN]
console.log(removeDuplicate(arr)) // [ 1, 2, 'abc', true, false, undefined ]

6. 利用Map

  • Map对象是JavaScript提供的一种数据结构,结构为键值对形式,将数组元素作为map的键存入,然后结合has()set()方法判断键是否重复
  • 使用Map()也可对NaN去重,原因是Map进行判断时认为NaN是与NaN相等的
function removeDuplicate(arr) {
  let newArr = []
  let map = new Map()
  arr.forEach(item => {
    if(!map.has(item)) {
      map.set(item, true)
      newArr.push(item)
    }
  })
  return newArr
}
const arr = [1, 2, 2, 'abc', 'abc', true, true, false, false, undefined, undefined, NaN, NaN]
console.log(removeDuplicate(arr)) // [ 1, 2, 'abc', true, false, undefined, NaN ]

7. 利用对象

  1. 基础版。不能区分2'2'
function removeDuplicate(arr) {
  let newArr = []
  let obj = {}
  let type = ''
  arr.forEach(item => {
    type = typeof item
    if(!obj[item]) {
      obj[item] = true
      newArr.push(item)
    }
  })
  return newArr
}
const arr = [1, 2, '2', 'abc', 'abc', true, true, false, false, undefined, undefined, NaN, NaN]
console.log(removeDuplicate(arr)) // [ 1, 2, 'abc', true, false, undefined, NaN ]
  1. 升级版。
function removeDuplicate(arr) {
  let newArr = []
  let obj = {}
  let type = ''
  arr.forEach(item => {
    type = typeof item
    if(!obj[item]) {
      obj[item] = [type]
      newArr.push(item)
    } else if(!obj[item].includes(type)) {
      obj[item].push(type)
      newArr.push(item)
    }
  })
  return newArr
}
const arr = [1, 2, '2', 'abc', 'abc', true, true, false, false, undefined, undefined, NaN, NaN]
console.log(removeDuplicate(arr)) // [ 1, 2, '2', 'abc', true, false, undefined, NaN ]

十、数组中出现最多的元素

function fn(arr) {
  let map = new Map()
  let maxNum = 0
  let maxElement = null
  arr.forEach(item => {
    if(map.has(item)) {
      map.set(item, map.get(item) + 1)
    } else {
      map.set(item, 1)
    }
    if(map.get(item) > maxNum) {
      maxNum = map.get(item)
      maxElement = item
    }
  })
  return '出现最多的是' + maxElement + ',一共出现了' + maxNum + '次'
}
var array = [1, 2, 3, 3, 3, 6, 6, 6, 6, 6, 7, 8, 9, '6', '3', '3', '3']
console.log(fn(array)) //出现最多的是6,一共出现了5次

十一、将二位有序数组合并为一维有序数组

function merge(left, right) {
  let result = []
  let i = 0, j = 0
  while(i < left.length && j < right.length) {
    if(left[i] > right[j]) {
      result.push(right[j++])
    } else {
      result.push(left[i++])
    }
  }
  while(i < left.length) {
    result.push(left[i++])
  }
  while(j < right.length) {
    result.push(right[j++])
  }
  return result
}
function mergeSort(arr) {
  if(arr.length == 1) return arr[0]
  while(arr.length > 1) {
    let left = arr.shift()
    let right = arr.shift()
    arr.push(merge(left,right))
  }
  return arr[0]
}

let arr1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 2, 3], [4, 5, 6]];
let arr2 = [[1, 4, 6], [7, 8, 10], [2, 6, 9], [3, 7, 13], [1, 5, 12]];
console.log(mergeSort(arr1))
console.log(mergeSort(arr2))