Array的方法简单整理

# 快速生成一个数组

//快速生成一个数组
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 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);
1
2
3
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;
},[]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 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
1
2
3
4
5
6
7
8
9

Array.isArray 实现

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

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

1
2
3
4
5
6

# 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"]
1
2
3
4
5
6
7
8
9
10
11
//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; 
 }
1
2
3
4
5
6
7
8
9
10

# 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]
1
2
3
4

插入

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]
1
2
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"]
1
2
3

# 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;
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 所有的数组方法集合

改变原数组的方法:


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

不改变原数组的方法:

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

# 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 对键持有弱引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

# SetMap 区别

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

# 相似之处
  1. 集合类型SetMap 都是集合类型,用于存储唯一的元素。
  2. 内置方法:两者都有类似的方法来操作其元素,例如添加、删除、查找、清空等。
  3. 迭代器:都提供了迭代器方法(如 keysvaluesentries)用于遍历集合中的元素。
  4. 迭代顺序:两者都保持插入元素的顺序,因此迭代时按照插入顺序进行。
# 不同之处
  1. 存储的元素
  • Set:存储的是一组唯一的值。值可以是任何类型,包括原始值和对象。
  • Map:存储的是一组键值对。键和值都可以是任何类型。
  1. 键和值
  • Set:每个元素即是值,没有键的概念。
  • Map:每个元素是一个 [key, value] 对,键和值都可以是任意类型。
  1. 方法
  • 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
    
    1
    2
    3
    4
    5
    6
  • 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
    
    1
    2
    3
    4
    5
    6

# 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;
});

1
2
3
4
5
6
7
8
9

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

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

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

中断方法:

(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"]
1
2
3
4
5
6
7
8
9
10

递归

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) 
1
2
3
4
5
6
7
8
9
10
11
12
13

循环

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;
}
1
2
3
4
5
6
7
8
9
10
11
12

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]
1
2
3
4
5
6
7

正则

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

# 数组快速随机排序

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;
})

1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 数组排序

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));
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

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

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
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

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

差集


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;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

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

在 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 判断两个对象是否相同

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

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 参考文档

MDN ARRAY (opens new window)