Skip to content
On this page

数组的方法

1. 数组改变自身的方法

TIP

会改变自身的方法有 9 个

pushpopreverseshiftsortspliceunshift、以及 ES6 新增的 copyWithInfill 方法

1、 shift:将第一个元素删除并且返回删除元素,空即为undefined

js
let a = arr.shift()
console.log(a)         // a
console.log(arr)       // ['b', 'c', 'd']

2、unshift:向数组开头添加元素,并返回新的长度

js
let a = arr.unshift(0)
console.log(a)        // 5 返回数组长度
console.log(arr)      // [0, 'a', 'b', 'c', 'd']

3、pop:删除最后一个并返回删除的元素

js
let a = arr.pop()
console.log(a)        // d
console.log(arr)      // ['a', 'b', 'c']

4、push:向数组末尾添加元素,并返回新的长度

js
let a = arr.push('f')
console.log(a)        // 5 返回数组长度
console.log(arr)      // ['a', 'b', 'c', 'd', 'f']

5、reverse:颠倒数组顺序

js
let a = arr.reverse()
console.log(a)        // ["d", "c", "b", "a"]
console.log(arr)      // ["d", "c", "b", "a"]

6、sort:对数组排序

js
let arr = ['c', 'a', 'd', 'b']
let a = arr.sort()
console.log(a)        // ['a', 'b', 'c', 'd']
console.log(arr)      // ['a', 'b', 'c', 'd']

7、splice:splice(start,length,item)删,增,替换数组元素,返回被删除数组,无删除则不返回

js
let a = arr.splice(1, 2, 'f')
console.log(a)        // 返回被删除的元素数组['b', 'c'] 
console.log(arr)      // 在添加的地方添加元素后的数组["a", "f", "d"]

8、copyWithin:方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。

js
let a = arr.copyWithin(1, 2,3)
console.log(a)  //返回被复制的元素数组 ['a', 'c', 'c', 'd']
console.log(arr)  //原元素数组已经改变 ['a', 'c', 'c', 'd']

9、fill:用一个元素填充原来的数组

js
let a = arr.fill('e', 2, 4);
console.log(a) // 返回它会改变调用它的 `this` 对象本身, 然后返回它['a', 'b', 'e', 'e'] 
console.log(arr) // ['a', 'b', 'e', 'e']

2. 数组不改变自身的方法

TIP

concat, join, slice, map,filter, forEach, some, every, reduce 等不改变原数组

1、concattargetArr.concat(otherArr\[,anyOtherArr\]) 连接多个数组,返回新的数组

js
let a = arr.concat(['e', 'f'])
console.log(a)        // 新数组 ["a", "b", "c", "d", "e", "f"]
console.log(arr)      // ["a", "b", "c", "d"] 不变

2、join:将数组中所有元素以参数作为分隔符放入一个字符

js
let a = arr.join('-')
console.log(a)        // 字符串 a-b-c-d
console.log(arr)      // ["a", "b", "c", "d"] 不变

3、slice:slice(start,end),返回选定元素

js
let a = arr.slice(1)
console.log(a)        // ["b", "c", "d"]
console.log(arr)      // ["a", "b", "c", "d"] 不变

3. 数组扁平化

递归方法

js
function flatten(arr) {
    let result = [];
    for(let i = 0; i < arr.length; i++) {
        if(Array.isArray(arr[i])) {
            result = result.concat(flatten(arr[i]));
        }else {
            result.push(arr[i]);
        }
    }
    return result;
}

迭代方法

js
function flatten(arr) {
    return arr.reduce((prev, next) => {
        return prev.concat(Array.isArray(next) ? flatten(next) : next);
    }, []);
}

扩展运算符

js
function flatten(arr) {
    while(arr.some(item => Array.isArray(item)) {
        arr = [].concat(...arr)
    }
}

split 和 toString

缺点是数字会被全部转成字符串

js
function flatten(arr) {
    return arr.toString().split(',')
}

ES6 Flat

js
function flatten(arr) {
    return arr.flat(Infinity)
}

可选降几层

js
function flatDeep(arr, d = 1) {
    return d > 0
        ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, d - 1) : val), [])
        : arr.slice()
}

4. 数组去重

TIP

性能最好的是 Set,最差的方法是 双循环

性能排序:Set > map > Array.sort + 一层遍历去重 > filter + indexOf > double for cycle

双循环

js
function distinct(arr) {
    for(let i = 0; i < arr.length; i++) {
        for(let j = i + 1; j < arr.length; j++) {
            if(arr[j] === arr[i]) {
                arr.splice(j, 1)
                j--; // 数组长度变了
            }
        }
    }
    return arr;
}

filter 和 indexOf

js
function distinct(a, b) {
    const arr = a.concat(b)
    return arr.filter((item, index) => {
        return arr.indexOf(item) === index;
    })
}

Set

js
const array = [1, 2, 2, 3, 1]
const res = [...new Set(array)];

Map

js
function uniqueArray(arr) {
    const map = new Map()
    const res = []
    for(let i = 0; i < arr.length; i++) {
        if(!map.get(arr[i])) {
            res.push(arr[i])
            map.set(arr[i], true)
        }
    }
    return res
}

Object 对象

js
function distinct(arr) {
    const obj = {}
    return arr.filter(item =>
        obj.hasOwnProperty(typeof item + item)
        ? false
        : (obj[typeof item + item] = true) // 存储有的值
    )
}

sort 排序

js
function unique(arr) {
    arr = arr.sort()
    let pointer = 0
    while(arr[pointer]) {
        if(arr[pointer]  != arr[pointer + 1]) { // 不相等,指针下移
            pointe++
        }else {
            arr.splice(pointer + 1, 1)
        }
    }
    return arr
}

5. flat

js
function flat(arr, depth) {
    if(!arr || depth < 0) return arr;
    return arr.reduce((prev, next) => {
        return prev.concat(Array.isArray(next) ? flat(next, depth - 1) : next)
    }, [])
}

6. push

js
Array.prototype.push = function() {
    for(let i = 0; i < arguments.length; i++) {
        this[this.length] = arguments[i];
    }
    return this.length // 返回长度
}

7. filter

js
Array.prototype.filter = function(fn) {
    if(typeof fn !== 'function') {
        console.error('type Error')
    }
    const res = []
    for(let i = 0; i < this.length; i++) {
        fn(this[i] && res.push(this[i]))
    }
    return res
}

8. map

js
Array.prototype.map = function(cb, context) {
    const arr = Array.prototype.slice.call(this)
    const res = []
    for(let i = 0; i < arr.length; i++) {
        res.push(cb.call(context, arr[i], i, this))
    }
    return res
}

9. reduce

js
Array.prototype.myReduce = function (fn, initVal) {
    let result = initVal, i = 0;
    if(typeof initVal === 'undefined') {
        result = this[i]
        i++;
    }
    // this 是一个数组
    while(i < this.length) {
        result = fn(result, this[i])
    }
    return result;
}

10. splice

js
const sliceDeleteElements = (array, startIndex, deleteCount, deleteArr) => {
    for (let i = 0; i < deleteCount; i++) {
        const index = startIndex + i
        if (index in array) {
            let current = array[index]
            deleteArr[i] = current
        }
    }
}

const movePostElements = (array, startIndex, len, deleteCount, addElements) => {
    if (deleteCount === addElements.length) {
        return
    } else if (deleteCount > addElements.length) {
        // 删除的元素比新增的元素多,那么后面的元素整体向前挪动
        // 一共需要挪动 len - startIndex - deleteCount 个元素
        for (let i = startIndex + deleteCount; i < len; i++) {
            let fromIndex = i
            let toIndex = i - (deleteCount - addElements.length) // 目标位置
            if (fromIndex in array) {
                array[toIndex] = array[fromIndex]
            } else {
                delete array[toIndex]
            }
        }
        // 注意注意!这里我们把后面的元素向前挪,相当于数组长度减小了,需要删除冗余元素
        // 目前长度为 len + addElements - deleteCount
        for (let i = len - 1; i >= len + addElements.length - deleteCount; i--) {
            delete array[i]
        }
    } else if (deleteCount < addElements.length) {
        // 删除的元素比新增的元素少,那么后面的元素整体向后挪动
        for (let i = len - 1; i >= startIndex + deleteCount; i--) {
            let fromIndex = i
            let toIndex = i + (addElements.length - deleteCount)
            if (fromIndex in array) {
                array[toIndex] = array[fromIndex]
            } else {
                delete array[toIndex]
            }
        }
    }
}


const computeStartIndex = (startIndex, len) => {
    // 处理索引负数的情况
    if (startIndex < 0) {
        return startIndex + len > 0 ? startIndex + len : 0
    }
    return startIndex >= len ? len : startIndex
}

const computeDeleteCount = (startIndex, len, deleteCount, argumentsLen) => {
    // 删除数目没有传,默认删除startIndex及后面所有的
    if (argumentsLen === 1)
        return len - startIndex
    // 删除数目过小
    if (deleteCount < 0)
        return 0
    // 删除数目过大
    if (deleteCount > len - deleteCount)
        return len - startIndex
    return deleteCount
}


Array.prototype._splice = function (start, deleteCount, ...addElements) {
    const argumentsLen = arguments.length
    const array = Object(this)
    const len = array.length
    const deleteArr = new Array(deleteCount) // 删除的数组,也就是要返回的东西

    startIndex = computeStartIndex(start, len)
    deleteCount = computeDeleteCount(startIndex, len, deleteCount, argumentsLen)

    // 判断 sealed 对象和 frozen 对象, 即 密封对象 和 冻结对象
    if (Object.isSealed(array) && deleteCount !== addElements.length) {
        throw new TypeError('the object is a sealed Object')
    } else if (Object.isFrozen(array) && (deleteCount > 0 || addElements.length > 0)) {
        throw new TypeError('the object is frozen object')
    }

    // 拷贝删除的元素
    sliceDeleteElements(array, startIndex, deleteCount, deleteArr)
    // 移动删除元素后面的元素
    movePostElements(array, startIndex, len, deleteCount, addElements)
    // 插入新元素
    for (let i = 0; i < addElements.length; i++) {
        array[startIndex + i] = addElements[i]
    }

    array.length = len - deleteCount + addElements.length
    return deleteArr
}

11. indexOf

  • 需要分 ArrayString 两种情况
js
function sIndexOf(str, searchStr, fromIndex = 0) {
    const regex = new RegExp(`${searchStr}`, 'ig');
    regex.lastIndex = fromIndex
    const result = regex.exec(str)
    return result ? result.index : -1
}

function aIndexOf(arr, elem, fromIndex = 0) {
    if(!elem) return -1
    for(let i = fromIndex; i < arr.length; i++) {
        if(arr[i] === elem) return i
    }
    return -1
}

function indexOf(items, elem, fromIndex = 0) {
    const isArray = Array.isArray(items)
    const isString = Object.prototype.toString.call(items) === '[object String]'
    if(!isArray && !isString) throw new SyntaxError()
    if(isArray) return aIndexOf(items, elem, fromIndex)
    return sIndexOf(items, elem, fromIndex) 
}

12. 计算多个区间的交集

TIP

1.计算多个区间的交集

  • 区间用长度为2的数字数组表示,如[2, 5]表示区间2到5(包括2和5);
  • 区间不限定方向,如[5, 2]等同于[2, 5];

实现getIntersection 函数

可接收多个区间,并返回所有区间的交集(用区间表示),如空集用null表示

示例:

  • getIntersection([5, 2], [4, 9], [3, 6]); // [4, 5]
  • getIntersection([1, 7], [8, 9]); // null
js
function getIntersection(...arr) {
    if(!arr || !arr.length) return null;
    // 排序数组
    arr.forEach(item => {
        item.sort((a, b) => a - b)
    })
    // 排序数组的数组
    arr.sort((a, b) => a[0] - b[0])
    const res = [...arr[0]]
    for(let i = 1; i < arr.length; i++) {
        if(res[1] < arr[i][0]) return null

        if(res[0] <= arr[i][0]) {
            res[0] = Math.max(res[0], arr[i][0])
            res[1] = Math.min(res[1], arr[i][1])
        }
    }
    return res;
}

13. 求数组的交集、差集、并集、补集

js
const a = [1, 2, 3, 4, 5];
const b = [2, 4, 6, 8, 10];
// 交集
const c = a.filter(v => b.indexOf(v) > -1)
// 差集
const d = a.filter(v => !b.includes(v))
// 补集
const e = a.filter(v => !b.includes(v)).concat(b.filter(v => !a.includes(v)))
// 并集
const f = a.concat(b.filter(v => !a.includes(v)))

console.log(c, d, e, f);

14. 不用for循环快速实现 [1, 2, ...100]

js
const t = new Array(100).fill(1).map((_, k) => k + 1)
const y = Array.from(new Array(100), (_, k) => k + 1)

Released under the MIT License.