Array的方法简单整理

[[toc]]

快速生成一个数组

//快速生成一个数组
Array.from(Array(100), (key, index) => index);

[...new Array(100).keys()]

Array(3).fill(''); //["", "", ""]

new Array(10).fill({}).map((item)=>{
return {
title:"掘金会员",
createtime:"2020-05-03",
state:1,
price:19.8,
timeNum:12,
userName:"虎克小哥哥",
age:18,
city:"上海"
}
})

//递归
let arr = [];
(function dfs(i) {
if (i < 100) {
arr.push(i);
dfs(++i);
}
}(0));

Array(100).join(",").split(",").map((key,index)=> index)

Array.apply(null,Array(100)).map((key,index)=>index)

some() & every()

every()与some()方法都是JS中数组的迭代方法。

some()是对数组中每一项运行给定函数,如果该函数对任一项返回true,则返回true;some一直在找符合条件的值,一旦找到,则不会继续迭代下去。

every()是对数组中每一项运行给定函数,如果该函数对每一项返回true,则返回true;every从迭代开始,一旦有一个不符合条件,则不会继续迭代下去。

reduce()

  • reducer 函数接收4个参数:

    • Accumulator (acc) (累计器,没有返回值为undefined)

    • CurrentValue (cur) (当前值)

    • CurrentIndex (idx) (当前索引)

    • SourceArray (ary) (原数组)

arr.reduce(function(Accumulator,CurrentValue,CurrentIndex,SourceArray){
...
}, init);
var arr = [3,9,4,3,6,0,9];

//求数组项之和
var sum = arr.reduce(function (prev, cur) {
return prev + cur;
},0);

//求数组项最大值
var max = arr.reduce(function (prev, cur) {
return Math.max(prev,cur);
});

Math.max(...arr);

//数组去重
var newArr = arr.reduce(function (prev, cur) {
prev.indexOf(cur) === -1 && prev.push(cur);
return prev;
},[]);

isArray()

Array.isArray() 用于确定传递的值是否是一个 Array。

Array.isArray([1, 2, 3]);  // true

Array.isArray({foo: 123}); //false


let dom1 = document.getElementsByClassName('token')
Array.isArray(dom1); //false
Array.isArray([...dom1]); //true
Array.isArray(Array.from(dom1)); //true

Array.isArray 实现

Array.myIsArray = function(o) {
return Object.prototype.toString.call(Object(o)) === '[object Array]';
};

console.log(Array.myIsArray([])); // true

slice()

请注意: 该方法并不会修改数组,而是返回一个子数组。如果想删除数组中的一段元素,应该使用方法 Array.splice()。

  • arr.slice(begin ,end?)
    • (包含 begin,但不包含 end)。
    • slice(1,4) 会提取原数组中从第二个元素开始一直到第四个元素的所有元素 (索引为 1, 2, 3的元素)。
const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
//[].slice.call(animals,1,3)

console.log(animals.slice(2));
// expected output: Array ["camel", "duck", "elephant"]

console.log(animals.slice(2, 4));
// expected output: Array ["camel", "duck"]

console.log(animals.slice(1, 5));
// expected output: Array ["bison", "camel", "duck", "elephant"]
//slice的内部实现
Array.prototype.slice = function(start,end){
var result = new Array();
start = start || 0;
end = end || this.length; //this指向调用的对象,当用了call后,能够改变this的指向,也就是指向传进来的对象,这是关键
for(var i = start; i < end; i++){
result.push(this[i]);
}
return result;
}

splice()

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

此方法会改变原数组

删除

第二个参数为删除的个数

var ary =[1,2,3,4,5,6]
//[].splice.call(ary,1,1)
ary.splice(1,1); // 返回删除的一项 [2]
ary //[1, 3, 4, 5, 6]

插入

var ary =[1,2,3,4,5,6]
ary.splice(2, 0, "7"); //[], 没有元素被删除
ary //[1, 2, "7", 3, 4, 5, 6]

ary.splice(2, 0, "9",'10',11,12)
ary //[1, 2, "9", "10", 11, 12, "7", 3, 4, 5, 6]

删除 & 插入

var myFish = ['angel', 'clown', 'trumpet', 'sturgeon'];
myFish.splice(0, 2, 'parrot', 'anemone', 'blue'); //["angel", "clown"]
myFish //["parrot", "anemone", "blue", "trumpet", "sturgeon"]

filter() 实现

filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。

注意: filter() 不会改变原始数组

注意: filter() 不会对空数组进行检测。

语法

array.filter(function(currentValue,index,arr), thisValue)

Array.prototype.selfFilter = function(callback, context) {
// 不能是null调用方法
if (this === null) {
throw new TypeError(
"Array.prototype.reduce" + "called on null or undefined"
);
}
// 第一个参数必须要为function
if (typeof callback !== "function") {
throw new TypeError(callback + " is not a function");
}
// 获取数组
let aArr = Array.prototype.slice.call(this);
let _len = aArr.length;
let aFArr = [];
// 循环调用callback
for (let i = 0; i < _len; i++) {
if (!aArr.hasOwnProperty(i)) {
continue;
}
callback.call(context, aArr[i], i, this) && aFArr.push(aArr[i]);
}
return aFArr;
};

所有的数组方法集合

改变原数组的方法:


pop():移除数组末尾的最后一个元素,并返回该元素的值。
push():向数组末尾添加一个或多个元素,并返回新数组的长度。
shift():移除数组的第一个元素,并返回该元素的值。
unshift():在数组的开头添加一个或多个元素,并返回新数组的长度。
splice():向/从数组中添加/删除项目,然后返回被删除的项目。
reverse():颠倒数组中元素的顺序。
sort():对数组的元素进行排序,并返回排序后的数组。
fill():使用一个固定值填充数组的所有元素。
copyWithin():从数组的指定位置拷贝元素到数组的另一个指定位置。
set() (TypedArray):用于通过拷贝数组或者数值来填充 TypedArray。

不改变原数组的方法:

concat():连接两个或多个数组,并返回一个新数组。
slice():从已有的数组中返回选定的元素。
join():把数组中的所有元素放入一个字符串。
indexOf():搜索数组中的元素,并返回它所在的位置索引,如果没有找到则返回 -1。
lastIndexOf():从数组的末尾开始搜索元素,并返回它所在的位置索引,如果没有找到则返回 -1。
includes():判断数组是否包含一个指定的值,如果是返回 true,否则返回 false。
every():检查数组中的所有元素是否都符合指定条件。
some():检查数组中是否至少有一个元素符合指定条件。
filter():创建一个新数组,其中包含所有通过所提供函数实现的测试的元素。
map():创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
forEach():对数组中的每个元素执行提供的函数。
reduce():对数组中的每个元素执行一个累积器函数(从左到右),将其结果汇总为单个返回值。
reduceRight():对数组中的每个元素执行一个累积器函数(从右到左),将其结果汇总为单个返回值。
find():返回数组中满足提供的测试函数的第一个元素的值,否则返回 undefined。
findIndex():返回数组中满足提供的测试函数的第一个元素的索引,否则返回 -1。

Map + Set + WeakMap + WeakSet

// Sets
const set = new Set();

// 添加值
set.add(1);
set.add(2);
set.add(3);
set.add(3); // 重复值不会被添加

// 检查是否存在某个值
console.log(set.has(1)); // true
console.log(set.has(4)); // false

// 获取 Set 的大小
console.log(set.size); // 3

// 删除值
set.delete(2);
console.log(set.has(2)); // false

// 遍历 Set 的值
for (const value of set.values()) {
console.log(`Value: ${value}`);
}

// 遍历 Set 的键(实际上是值,因为 Set 没有键)
for (const key of set.keys()) {
console.log(`Key: ${key}`);
}

// 遍历 Set 的键值对([value, value] 数组)
for (const [key, value] of set.entries()) {
console.log(`Entry: ${key} = ${value}`);
}

// 使用 forEach 遍历 Set
set.forEach((value) => {
console.log(`ForEach Value: ${value}`);
});

// 清空 Set
set.clear();
console.log(set.size); // 0


// WeakSet
// WeakSet 是 JavaScript 中的一种集合类型,它与 Set 类似,但有一些关键区别和限制。WeakSet 只能存储对象类型的值,并且对这些对象持有弱引用,这意味着如果没有其他引用指向这些对象,它们可以被垃圾回收机制回收。
const weakSet = new WeakSet();
const obj1 = {};
const obj2 = {};
const obj3 = {};

// 添加对象到 WeakSet
weakSet.add(obj1);
weakSet.add(obj2);

// 检查对象是否存在于 WeakSet 中
console.log(weakSet.has(obj1)); // true
console.log(weakSet.has(obj3)); // false

// 删除对象
weakSet.delete(obj2);
console.log(weakSet.has(obj2)); // false

// 清除引用以便垃圾回收
obj1 = null;
obj3 = null;

// 在这里,obj1 会被垃圾回收机制回收,因为 WeakSet 对其持有弱引用


// Map **
const map = new Map();

// 添加键值对
map.set('key1', 'value1');
map.set('key2', 'value2');
map.set('key3', 'value3');

// 获取值
console.log(map.get('key1')); // 'value1'

// 检查键是否存在
console.log(map.has('key2')); // true

// 删除键值对
map.delete('key2');
console.log(map.has('key2')); // false

// 获取 Map 的大小
console.log(map.size); // 2

// 遍历 Map 的键
for (const key of map.keys()) {
console.log(`Key: ${key}`);
}

// 遍历 Map 的值
for (const value of map.values()) {
console.log(`Value: ${value}`);
}

// 遍历 Map 的键值对
for (const [key, value] of map.entries()) {
console.log(`Entry: ${key} = ${value}`);
}

// 使用 forEach 遍历 Map
map.forEach((value, key) => {
console.log(`${key}: ${value}`);
});

// 清空 Map
map.clear();
console.log(map.size); // 0


// WeakMap **
// WeakMap 对象在 JavaScript 中也提供了一套方法用于操作其键值对。与 Map 对象不同的是,WeakMap 只能使用对象作为键,并且键是弱引用,这意味着如果没有其他引用指向该对象,则该对象可以被垃圾回收。
const weakMap = new WeakMap();
const obj1 = {};
const obj2 = {};
const obj3 = {};

// 添加键值对
weakMap.set(obj1, 'value1');
weakMap.set(obj2, 'value2');
weakMap.set(obj3, 'value3');

// 获取值
console.log(weakMap.get(obj1)); // 'value1'

// 检查键是否存在
console.log(weakMap.has(obj2)); // true

// 删除键值对
weakMap.delete(obj2);
console.log(weakMap.has(obj2)); // false

// 尝试获取已删除的键的值
console.log(weakMap.get(obj2)); // undefined

// 清除引用以便垃圾回收
obj1 = null;
obj3 = null;

// 在这里,obj1 和 obj3 的键值对会被垃圾回收机制回收,因为 WeakMap 对键持有弱引用

SetMap 区别

SetMap 在 JavaScript 中确实有许多相似之处,但它们在用途和行为上有显著的区别。下面是对两者的详细比较:

相似之处
  1. 集合类型SetMap 都是集合类型,用于存储唯一的元素。
  2. 内置方法:两者都有类似的方法来操作其元素,例如添加、删除、查找、清空等。
  3. 迭代器:都提供了迭代器方法(如 keysvaluesentries)用于遍历集合中的元素。
  4. 迭代顺序:两者都保持插入元素的顺序,因此迭代时按照插入顺序进行。
不同之处
  1. 存储的元素
    • Set:存储的是一组唯一的值。值可以是任何类型,包括原始值和对象。
    • Map:存储的是一组键值对。键和值都可以是任何类型。
  2. 键和值
    • Set:每个元素即是值,没有键的概念。
    • Map:每个元素是一个 [key, value] 对,键和值都可以是任意类型。
  3. 方法
    • Set
      • add(value):添加一个值到集合中。
      • has(value):检查集合中是否存在某个值。
      • delete(value):从集合中删除一个值。
      • clear():清空集合。
      • values()keys()entries()forEach():用于迭代集合中的值。
    • Map
      • set(key, value):添加或更新一个键值对。
      • get(key):获取与键关联的值。
      • has(key):检查集合中是否存在某个键。
      • delete(key):从集合中删除一个键值对。
      • clear():清空集合。
      • values()keys()entries()forEach():用于迭代集合中的键值对。
用途和使用场景
  • Set

    • 用于存储唯一值的集合,可以用于数组去重。
    • 适用于需要快速查找唯一值的场景。

    示例:

    const set = new Set();
    set.add(1);
    set.add(2);
    set.add(2); // 不会添加重复值
    console.log(set.has(1)); // true
    console.log(set.size); // 2
  • Map

    • 用于存储键值对,特别适合需要基于键进行快速查找、添加和删除操作的场景。
    • 适用于需要关联数据对的场景,比如字典、缓存等。

    示例:

    const map = new Map();
    map.set('key1', 'value1');
    map.set('key2', 'value2');
    console.log(map.get('key1')); // 'value1'
    console.log(map.has('key2')); // true
    console.log(map.size); // 2

ObjectMap 区别

Map 和普通的对象(Object)在存储键值对的基本功能上有些类似,但它们在设计目的和使用场景上有一些重要的区别和优势:

区别和优势
键的类型:

Object:键必须是字符串或者 Symbol 类型。如果键不是字符串或者 Symbol,则会被转换为字符串。
Map:键可以是任意类型,包括基本类型(如字符串、数字、布尔值)、对象和函数等。这使得 Map 在处理复杂的键值关系时更加灵活。
插入顺序:

Object:对象的属性在添加时不保证任何顺序,遍历时的顺序可能不同于添加时的顺序。
Map:保持键值对的插入顺序,迭代时按照插入顺序进行,这点与 Array 类似。
性能:

Object:对象适合于存储简单的键值对,并且在属性较少、直接量赋值的情况下性能很好。
Map:Map 在处理大量数据、频繁增删键值对、需要快速查找特定键等方面通常比对象更高效。
可迭代性:

Object:需要额外处理才能进行迭代,比如使用 Object.keys(obj)、Object.values(obj) 或者 Object.entries(obj)。
Map:直接支持迭代器接口,可以通过 for…of、forEach 等方式遍历键值对。
内存管理:

Object:作为引用类型,对象属性被引用时会增加对象的引用计数,可能导致对象不被及时回收。
Map:对键的引用是弱引用,这意味着即使 Map 持有对象的引用,该对象也可以被垃圾回收。

数组去重

// 数组去重
function unique(arr, fn) {
return arr.reduce(fn, []);
}
unique([1,2,3,3,2,1,15,6], function(arr, item) {
!arr.includes(item) && arr.push(item);
return arr;
});

forEach中return有效果吗?如何中断forEach循环?

在forEach中用return不会返回,函数会继续执行。

let nums = [1, 2, 3];
nums.forEach((item, index) => {
return;//无效
})

中断方法:

(1). 使用try监视代码块,在需要中断的地方抛出异常。

(2). 官方推荐方法(替换方法):用every和some替代forEach函数。every在碰到return false的时候,中止循环。some在碰到return true的时候,中止循环

js将多维数组转换为一维数组


let arr = [1, 2, 3, 4, 5, [6, 7, 8, [9, 10, 11, 12, [13, 14, 15, 16]]]]
console.log(arr.join()) // 输出为:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16

let newArr = arr.join().split(',')
let newArr = arr.toString().split(',')
let newArr = (arr + '').split(',')


console.log(newArr) // 输出为:["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"]

递归

let arr = [1, 2, 3, 4, 5, [6, 7, 8, [9, 10, 11, 12, [13, 14, 15, 16]]]]
let newArr = [] // 存放转化后的一维数组
function arrConversion (arr) {
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
arrConversion(arr[i])
} else {
newArr.push(arr[i])
}
}
}
arrConversion(arr)
console.log(newArr)

循环

function flatArray(ary) {
let result = [];
while (ary.length) {
let item = ary.shift();
if (Array.isArray(item)) {
ary.unshift(...item);
} else {
result.push(item);
}
}
return result;
}

flat

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

// 指定转换的嵌套层数
console.log([1, [2, [3, [4, 5]]]].flat(2)); // [1, 2, 3, [4, 5]]

// 不管嵌套多少层
console.log([1, [2, [3, [4, 5]]]].flat(Infinity)); // [1, 2, 3, 4, 5]

正则

let ary = [1, [2, [3, [4, 5]]], 6];
let str = JSON.stringify(ary);
let result = str.replace(/(\[|\])/g, '').split(',');
console.log( result )

数组快速随机排序

let arr =[1,2,3,4];
//方法一
let t;
for(let i = 0;i < arr.length; i++){
let rand = parseInt(Math.random()*arr.length);
t = arr[rand];
arr[rand] =arr[i];
arr[i] = t;
}
//方法二
arr.sort(()=>{
return Math.random() - 0.5;
})

数组排序

function selectSort(arr) {
var len = arr.length;
for(let i = 0 ;i < len - 1; i++) {
for(let j = i ; j<len; j++) {
if(arr[j] < arr[i]) {
[arr[i],arr[j]] = [arr[j],arr[i]];
}
}
}
return arr
}

function quickSort(arr) {
if(arr.length <= 1) {
return arr; //递归出口
}
var left = [],
right = [],
current = arr.splice(0,1);
for(let i = 0; i < arr.length; i++) {
if(arr[i] < current) {
left.push(arr[i]) //放在左边
} else {
right.push(arr[i]) //放在右边
}
}
return quickSort(left).concat(current,quickSort(right));
}

判断数组中是否有重复元素

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

function isRepeat(arr) {
let flag = false;
for(var i = 0; i < arr.length; i++) {
for(var j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
flag = true;
break;
}
}
}
return flag
}

function isRepeat(arr) {
let obj = {}
for(var i = 0; i < arr.length; i++) {
obj[arr[i]] = arr[i]
}
return Object.keys(obj).length !== arr.length
}

求第一个数组中没有第二个数组中部分的值

差集


function differenceSecond(ary1,ary2){
let arr = []
ary1.filter((item)=>{
!ary2.includes(item)&&arr.push(item)
})
return arr
}

function differenceSecond(m, n) {
let a = [...m, ...n];
let b = n;
let aHasNaN = m.some(function(v) {
return isNaN(v);
});
let bHasNaN = n.some(function(v) {
return isNaN(v);
});
let difference = a
.filter(function(v) {
return b.indexOf(v) == -1 && !isNaN(v);
})
.concat(
b.filter(function(v) {
return a.indexOf(v) == -1 && !isNaN(v);
})
)
.concat(aHasNaN ^ bHasNaN ? [NaN] : []);
return difference;
}

简单实现判断两个数组是不是相同

在 JavaScript 中,可以通过以下步骤来实现这一点:

检查数组的长度是否相同。

如果长度相同,逐个比较对应位置上的元素。

下面是一个示例函数,用于判断两个数组是否相同:

function arraysAreEqual(arr1, arr2) {
// 检查长度是否相同
if (arr1.length !== arr2.length) {
return false;
}

// 逐个比较元素
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) {
return false;
}
}

// 如果通过了所有检查,返回 true
return true;
}

// 测试示例
const array1 = [1, 2, 3, 4];
const array2 = [1, 2, 3, 4];
const array3 = [1, 2, 3, 5];

console.log(arraysAreEqual(array1, array2)); // 输出 true
console.log(arraysAreEqual(array1, array3)); // 输出 false

判断两个对象是否相同

要判断两个对象是否相同,需要进行深度比较,因为直接比较对象的引用(使用 === 或 ==)只会检查它们是否引用同一个内存地址,而不是检查它们的内容是否相同。

function deepEqual(obj1, obj2) {
// 如果两个对象引用同一内存地址,直接返回 true
if (obj1 === obj2) {
return true;
}

// 如果两个对象类型不同,或者有一个不是对象,返回 false
if (typeof obj1 !== 'object' || typeof obj2 !== 'object' || obj1 === null || obj2 === null) {
return false;
}

// 获取对象的键数组
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);

// 如果键的数量不同,返回 false
if (keys1.length !== keys2.length) {
return false;
}

// 遍历键并递归比较每个属性
for (let key of keys1) {
if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
return false;
}
}

return true;
}

// 测试示例
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { a: 1, b: { c: 2 } };
const obj3 = { a: 1, b: { c: 3 } };

console.log(deepEqual(obj1, obj2)); // 输出 true
console.log(deepEqual(obj1, obj3)); // 输出 false

参考文档

MDN ARRAY