0%

数组类型

数组是多个变量值的集合,数组是Array 对象的实例,所以可以像对象一样调用方法。

声明数组

创建数组

使用对象方式创建数组

1
console.log(new Array(1, '阿顺', 'Ashun')); //[1, "阿顺", "Ashun"]

使用字面量创建是推荐的简单作法

1
const array = ["ashun", "Ashun"];

多维数组定义

1
2
3
const array = [["ashun"], ["Ashun"]];					//字面量
const arr = new Array(["ashun"], ["Ashun"]); //构造函数
console.log(array[1][0], arr[1][0]);

数组是引用类型可以使用const声明并修改它的值

1
2
3
const array = ["Ashun", "ashun"];
array.push("ashuntefannao");
console.log(array);

使用原型的 length属性可以获取数组元素数量

1
2
let as= ["Ashun", "ashun"];
console.log(as.length); //2

数组可以设置任何值,下面是使用索引添加数组

1
2
let as = ["阿顺"];
as[1] = "ashun";

下面直接设置3号数组,会将1,2索引的数组定义为空值

1
2
3
let Arr = ["ashun"];
Arr[3] = "Ashun";
console.log(Arr, Arr[2]); //["ashun", empty × 2, "Ashun"] undefined

声明多个空元素的数组

1
2
3
let arr = new Array(3);		//仅传入一个参数且为Number,会创建对应长度的空Array
console.log(arr.length);
console.log(arr);
Array.of

使用Array.ofnew Array 不同的是:仅传入一个参数且为Number,不会创建空元素的Array

1
2
3
4
5
let as = Array.of(3);
console.log(as); //[3]

as = Array.of(1, 2, 3);
console.log(as); //[1, 2, 3]

类型检测

检测变量是否为数组类型

  • 内置方法Array.isArray(msg)
  • instanceof
1
2
3
console.log(Array.isArray(1));					//false
console.log(Array.isArray(["ashun"])); //true
console.log([] instanceof Array); //true

类型转换

​ 在js中,灵活的将各种数据类型转换,使用不同的方法进行处理,能够快速的解决很多问题。

->String

大部分数据类型都可以使用.toString() 函数转换为字符串。

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

也可以使用函数 String() 转换为字符串。

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

或使用join()连接为字符串

1
console.log([1, 2, 3].join("-"));//1-2-3

Array.from

使用Array.from可将类数组转换为数组,类数组指包含 length 属性或可迭代的对象。

  • 第一个参数为要转换的数据,第二个参数为类似于map 函数的回调方法
1
2
let str = '阿顺';
console.log(Array.from(str)); //["阿", "顺"]

为对象设置length属性后也可以转换为数组,但要下标为数值或数值字符串

1
2
3
4
5
6
let user = {
0: '阿顺',
'1': 18,
length: 2
};
console.log(Array.from(user)); //["阿顺", 18]

DOM元素转换为数组后来使用数组函数,第二个参数类似于map 函数的方法,可对数组元素进行处理。

  • querySelectorAll返回的是一个类数组的Object,但不是数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<body>
<button>Ashun</button>
<button>Ashuntefannao.com</button>
</body>

<script>
let btns = document.querySelectorAll("button");

console.log(btns instanceof Array); //false
console.log(btns instanceof Object); //true

console.dir(btns); /*NodeList{0:button,1:button,length:2}*/

Array.from(btns, (val) => {
val.style.backgroundColor = "red";
});
</script>

展开语法

使用...展开语法将 NodeList 转换为数组操作。

  • forEach可以直接操作Dom,但是map方法只能被Array调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<style>
.active {
background-color: pink;
}
</style>

<body>
<button>Ashun</button>
<button>Ashuntefannao.com</button>
</body>

<script>
let btns = document.querySelectorAll("button");
[...btns].map((v) => {
v.addEventListener("click", (e) =>
console.log(e.target.classList.toggle("active"))
);
});
</script>

展开语法

...即展开语法,功能有两个,介绍如下:

  • 将Array拆分为多个独立数据元 (作为表达式使用时)
  • 将多个独立数据元合并为Array (在形参、实参中使用时)
拆分

利用拆分功能,合并数组

1
2
3
4
let arr = ["ashun", "Ashun"];
let arr1 = [1, 2, ...arr];
console.log(arr1);
//[1, 2, "ashun", "Ashun"]

将Array拆分,传入Math.max

1
2
let nums = [1, 2, 3];
console.log(Math.max(...nums));//3

合并

函数接收多个参数转为Array

1
2
3
4
function test(...argu) {
console.log(argu);
}
test("ashun", "Ashun");//["ashun", "Ashun"]
1
2
3
4
5
function test(a, ...argu) {
console.log(a); //ashun
console.log(argu); //[1, "site:Ashuntefannao.com"]
}
test("ashun", 1, "site:Ashuntefannao.com");

定义实参,合并接收多个数组元素

1
2
let [name, ...argus] = ["AHSUN", "CSS3", "ES6", "Node"];
console.log(argus); //["CSS3", "ES6", "Node"]

节点转换

​ 之前已经遇到过此问题:通过querySelectAll获取多个Dom节点,但是不能够使用Array的map等方法。原因是querySelectAll返回的是一个类数组的Object(NodeList),但其并不是Array,自然也就不能够使用Array的方法。但是forEach能够直接操作Dom。

学习后面章节后也可以使用原型处理,将Dom节点传入,那么Array的map方法在执行时,也就拥有了Dom的context(执行上下文),也就能够操作Dom节点。

1
2
3
4
5
6
7
8
9
10
11
<body>
<button>Ashun</button>
<button>Ashuntefannao.com</button>
</body>

<script>
let btns = document.querySelectorAll("button");
Array.prototype.map.call(btns,(item)=>{
item.style.background = 'red';
});
</script>

解构赋值

基本使用

下面是基本使用语法

1
2
let [name, age] = ["ashun", 18];
console.log(name, age);

函数返回结果也可解构赋值

1
2
3
4
5
function getInfo() {
return ["ASHUN", 18];
}
let [name, age] = getInfo();
console.log(name);//ASHUN

剩余解构:指用一个变量来接收剩余参数

1
2
let [name, ...args] = ["ashun", "ashuntefannao.com", "ES6", "Vue"];
console.log(args);

字符串也可进行解构

1
2
3
4
"use strict";
let str = "Ashun";
let [...nameItems] = str;
console.log(nameItems); //["A", "s", "h", "u", "n"]

严格模式

非严格模式可以不使用声明指令,严格模式下必须使用声明。所以建议养成先声明后使用的好习惯。

1
2
3
4
"use strict";
[web, url] = ["ashun.com", "ashuntefannao.com"];
console.log(web, url);
//Uncaught ReferenceError: web is not defined
1
2
3
"use strict";
let [web, url] = ["ashun.com", "ashuntefannao.com"];
console.log(web, url); //ashun.com ashuntefannao.com

设置默认值

可在解构的同时,设置默认值。

1
2
let [name, age = 18] = ["ashun"];
console.log(age);//18
函数参数赋值

若函数接收Array为参数,也可利用解构。

1
2
3
4
function test([a,b]){
console.log(a,b); //18 ashun
}
test(["18","ashun"]);

管理元素

基本使用

利用索引,改变Array

1
2
3
let arr = [1, "Ashun", "ashun"];
arr[1] = "Ashuntefannao";
console.log(arr); //[1, "Ashuntefannao", "ashun"]

向数组追加元素

1
2
3
let arr = [1, "Ashun"];
arr[arr.length] = "Ashuntefannao";
console.log(arr); //[1, "Ashun", "Ashuntefannao"]

扩展语法

使用展示语法批量添加元素

1
2
3
4
let arr = ["A", "s"];
let arr1 = ["h", "u", "n"];
arr.push(...arr1);
console.log(arr); //["A", "s", "h", "u", "n"]

push

压入元素,直接改变元数组,返回值为数组长度

1
2
3
let arr = ["ashun", 18, "AshunTeFanNao"];
console.log(arr.push("ashun.com")); //4
console.log(arr); //["ashun", 18, "AshunTeFanNao", "ashun.com"]

根据区间创建新数组

1
2
3
4
5
6
7
8
function rangeArray(begin, end) {
let newArr = [];
for (let i = begin; i <= end; i++) {
newArr.push(i);
}
return newArr;
}
console.log(rangeArray(2, 5)); //[1, 2, 3, 4, 5, 6]
pop

从末尾弹出元素,直接改变元数组,返回值为弹出的元素

1
2
3
let arr = ["Ashun", "王五"];
console.log(arr.pop()); //王五
console.log(arr); //["Ashun"]
shift

从数组前面取出一个元素,返回值为弹出的元素

1
2
3
let arr = ["王五", "Ashun"];
console.log(arr.shift()); //王五
console.log(arr); //["Ashun"]
unshift

从数组前面添加元素,返回值为数组长度

1
2
3
let arr = ["u", "n"];
console.log(arr.unshift('s', 'h')); //4
console.log(arr); //["a","s","h","u","n"]
栈和队列

​ 利用pushshift能够模拟队列操作(先进先出),利用unshiftshift能够模拟栈操作,操作栈顶(后进先出)。

小总结

  • push、unshift都是新增数据,返回结果为Array.length
  • pop、shift都是弹出数据,返回结果为弹出的元素。

fill
  • 参数1:填充的元素
  • 参数2、3:规定填充的范围,区间左闭右开[n1,n2)

使用fill 填充数组元素

1
2
console.dir(new Array(3).fill("SHUN")); //["SHUN", "SHUN", "SHUN"]
//empty×3 -> ["SHUN", "SHUN", "SHUN"]

fill能够覆盖原来的数据

1
2
3
let arr = [1, 2, 3];
arr.fill("Ashun");
console.log(arr); //["Ashun", "Ashun", "Ashun"]

指定填充位置

1
2
let arr = [1, 2, 3];
console.log(arr.fill("ashun", 1, 2));//[1, "ashun", 3]

slice

该方法的使用规则与string.slice()相同,同时也不会改变原数组,而是返回一个新Array。

1
2
3
let arr = [1, 2, 3];
console.log(arr.slice(2, 3));//[3]
console.log(arr);//[1, 2, 3]

不传参时,获取所有元素

1
2
let arr = [0, 1, 2, 3, 4, 5, 6];
console.log(arr.slice()); //[0, 1, 2, 3, 4, 5, 6]

splice

使用 splice 方法可以实现添加、删除、替换操作,会对原数组进行改变,返回值为删除的元素

该方法可接受多个参数:

  • 参数1:操作的位置
  • 参数2:删除的个数
  • 参数3~n:新增的元素
1
2
3
let arr = [0, 1, 2, 3, 4, 5, 6];
console.log(arr.splice(1, 3)); //返回删除的元素 [1, 2, 3]
console.log(arr); //删除数据后的原数组 [0, 4, 5, 6]

通过修改length删除最后一个元素

1
2
3
let arr = ["ashun", "Ashun"];
arr.length = arr.length - 1;
console.log(arr);

通过指定第3~n个参数来设置在删除位置添加的元素

1
2
3
let arr = [0, 1, 2, 3, 4, 5, 6];
console.log(arr.splice(1, 3, "Ashun", "SHUN")); //[1, 2, 3]
console.log(arr); //[0, "Ashun", "SHUN", 4, 5, 6]

向末尾添加元素

1
2
3
let arr = [0, 1, 2, 3, 4, 5, 6];
console.log(arr.splice(arr.length, 0, 'ashun', 'SHUN')); //[]
console.log(arr); // [0, 1, 2, 3, 4, 5, 6, "ashun", "SHUN"]

向数组前添加元素

1
2
3
let arr = [0, 1, 2, 3, 4, 5, 6];
console.log(arr.splice(0, 0, 'ashun', 'SHUN')); //[]
console.log(arr); //["ashun", "SHUN", 0, 1, 2, 3, 4, 5, 6]

数组元素位置调整函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function moveArrayItem(arr, begin, num, to) {
if (begin < 0 || to > arr.length) {
throw new Error("操作范围有误");
}
if (arr.length - begin < num) {
throw new Error("删除的数据超出数组的操作长度");
}

let newArr = [...arr];
let movePart = newArr.splice(begin, num);
newArr.splice(to, 0, ...movePart);
return newArr;
}
let arr = [1, 2, 3, 4, 5, 6];
console.log(moveArrayItem(arr, 0, 3, arr.length)); //[4, 5, 6, 1, 2, 3]
console.log(arr); //[1, 2, 3, 4, 5, 6]

可将方法添加到原型上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Array.prototype.moveArrayItem = function (begin, num, to) {
if (begin < 0 || to > this.length) {
throw new Error("操作范围有误");
}
if (this.length - begin < num) {
throw new Error("删除的数据超出数组的操作长度");
}

let newArr = [...this];
const movePart = newArr.splice(begin, num);
newArr.splice(to, 0, ...movePart);
return newArr;
};

let arr = [1, 2, 3, 4, 5, 6];
console.log(arr.moveArrayItem(0, 6, arr.length));
console.log(arr);

清空数组

将数组值修改为[]可以清空数组,如果有多个变量引用时,清空其中一个变量,不会影响其它变量对数组内存地址的引用,数组data在内存中依旧存在,被其他变量引用。除非清空所有变量对数组的引用时,才会进行垃圾回收。

1
2
3
4
5
6
7
8
9
10
11
12
13
let user = [
{ name: "ashun", type: "Controller" },
{ name: "wangwu", type: "user" },
];
let arr = user;
user = [];
console.log(arr);
/*
[{ name: "ashun", type: "Controller" },
{ name: "wangwu", type: "user" }]
*/
arr = [];
console.log(arr, user); //[] []

将数组length设置为0也可以清空数组

1
2
3
4
5
6
let user = [
{ name: "ashun", type: "Controller" },
{ name: "wangwu", type: "user" },
];
user.length = 0;
console.log(user);

使用splice方法删除所有数组元素

1
2
3
let user = [{ name: "ashun" }, { name: "SHUN" }];
user.splice(0, user.length);
console.log(user);

使用pop/shift删除所有元素,来清空数组

1
2
3
let user = [{ name: "ashun" }, { name: "SHUN" }];
while (user.pop()) {}
console.log(user);

合并操作

除了之前介绍的方式:...展开语法、join(str)合并为String。

还有一个属于数组的合并方法:arr.concat(arr1,……arrN),能够将多个数组合并在一起,该方法不会改变原数组。

1
2
3
let arr = ["ashun", "Ashun"];
console.log(arr.concat(["ASHUN", "TeFanNao"]));//["ashun", "Ashun", "ASHUN", "TeFanNao"]
console.log(arr);//["ashun", "Ashun"]
  • 当传入的参数也为Array时,在合并时会自动将其展开一层。
1
2
3
4
let as = ["a"];
console.log(as.concat("b")); //["a","b"]
console.log(as.concat("c",["d","e"],[[[["f"]]]])); //["a","c","d","e",[[["f"]]]];
console.log(as); //["a"]

copyWithin

使用 copyWithin 从数组中复制一部分到同数组中的另一个位置。(该方法会改变原数组)

语法说明

1
array.copyWithin(target, start, end)

参数说明

参数 描述
target 必需。复制到指定目标索引位置。
start 可选。元素复制的起始位置。
end 可选。停止复制的索引位置 (默认为 array.length)。如果为负值,表示倒数。

start、end区间左闭右开

1
2
3
const arr = [1, 2, 3, 4];
arr.copyWithin(2, 0, 2)
console.log(arr); //[1, 2, 1, 2]

查找元素

数组包含多种查找的函数,需要把这些函数掌握清楚,然后根据不同场景选择合适的函数。

indexOf、lastIndexOf、includes只能查找非引用类型元素。使用方式同string.indexOf()/lastIndexOf()/indeludes()

find、findIndex能够查找引用类型元素

indexOf

使用 indexOf 从前向后查找元素出现的位置,如果找不到返回 -1

1
2
let arr = [7, 3, 2, 8, 2, 6];
console.log(arr.indexOf(2)); // 2 从前面查找2出现的位置

如下面代码一下,使用 indexOf 查找字符串将找不到,因为indexOf 类似于===是严格类型约束。

1
2
let arr = [7, 3, 2, '8', 2, 6];
console.log(arr.indexOf(8)); // -1

第二个参数用于指定查找开始位置

1
2
3
let arr = [7, 3, 2, 8, 2, 6];
//从第二个元素开始向后查找
console.log(arr.indexOf(2, 3)); //4

lastIndexOf

使用 lastIndexOf 从后向前查找元素出现的位置,如果找不到返回 -1

1
2
let arr = [7, 3, 2, 8, 2, 6];
console.log(arr.lastIndexOf(2)); // 4 从后查找2出现的位置

第二个参数用于指定查找开始位置

1
2
3
4
5
6
let arr = [7, 3, 2, 8, 2, 6];
//从第五个元素向前查找
console.log(arr.lastIndexOf(2, 5));

//从最后一个字符向前查找
console.log(arr.lastIndexOf(2, -2));

includes

使用 includes 查找字符串返回值是布尔类型更方便判断

1
2
let arr = [7, 3, 2, 6];
console.log(arr.includes(6)); //true

我们来实现一个自已经的includes函数,来加深对includes方法的了解

1
2
3
4
5
6
7
function includes(array, item) {
for (const value of array)
if (item === value) return true;
return false;
}

console.log(includes([1, 2, 3, 4], 3)); //true

find

find 方法找到后会把值返回出来,且只返回第一次找到的值,不继续查找。如果找不到返回值为undefined

  • 参数是一个callback:(val,index,arr)=>{return Boolean}
  • callback必须返回一个boolean,就是通过这个boolean判断是否找到目标元素。
1
2
3
let arr = ["ashun", "Ashun", "SHUN"];
console.log(arr.find((v) => v === "SHUN"));//SHUN
console.log(arr.find((v) => true));//ashun

使用includes、indexOf、lastIndexOf不能查找引用类型,因为它们的内存地址是不相等的

1
2
3
4
5
6
7
let user = [
{ name: "ashun", type: "Controller" },
{ name: "wangwu", type: "user" },
];
console.log(user.includes({ name: "wangwu", type: "user" }));//false
console.log(user.indexOf({ name: "wangwu", type: "user" }));//-1
console.log(user.lastIndexOf({ name: "wangwu", type: "user" }));//-1

find 可以方便的查找引用类型

1
2
3
4
5
6
let user = [
{ name: "ashun", type: "Controller" },
{ name: "wangwu", type: "user" },
];
let find=user.find((v) => v.type == "Controller");
console.log(find);//{name: "ashun", type: "Controller"}

findIndex

findIndexfind 的区别是返回索引值。其余用法相同。

  • 查找不到时返回 -1
1
2
3
4
5
6
7
8
let arr = [7, 3, 2, '8', 2, 6];

console.log(arr.findIndex(function (v) {
return v == 8;
})); //3

console.log(8 == "8");//true
console.log(8 === "8");//false

find原理

下面使用自定义函数

1
2
3
4
5
6
7
8
9
10
11
let arr = [1, 2, 3, 4, 5];
function find(array, callback) {
for (const value of array) {
if (callback(value) === true) return value;
}
return undefined;
}
let res = find(arr, function(item) {
return item == 23;
});
console.log(res);
1
2
3
4
5
6
7
8
9
10
11
12
function Find(arr, callback) {
for (let i = 0; i < arr.length; i++) {
if (callback(arr[i], i, arr)) {
return arr[i];
}
}
return undefined;
}

let arr = ["ashun", "Ashun", "SHUN"];
let find = Find(arr, (val, index, arr) => val == "SHUN");
console.log(find);//SHUN

下面添加原型方法实现

1
2
3
4
5
6
7
8
9
10
Array.prototype.Find = function (callback) {
for (let i = 0; i < this.length; i++) {
if (callback(this[i], i, this)) return this[i];
}
return undefined;
};

let arr = [7, 3, 2, "8", 2, 6];
let find = arr.Find((val, index, arr) => index == 3);
console.log(find);//'8'

数组排序

reverse

反转数组顺序,该方法会改变原数组

1
2
3
let arr = [1, 4, 2, 9];
arr.reverse();
console.log(arr)//[9, 2, 4, 1]
sort
1
sort`每次使用两个值进行比较 `Array.sort((a,b)=>a-b)
  • 返回负数 a 排在 b前面,从小到大,a-b
  • 返回正数 b 排在a 前面,b-a
  • 返回 0 时保持不变
  • 该方法也会改变原数组

默认从小到大排序数组元素

1
2
let arr = [1, 4, 2, 9];
console.log(arr.sort()); //[1, 2, 4, 9]
1
2
3
4
5
6
7
8
9
let arr = [8, 4, 5, 2, 1, 7];
arr.sort((a, b) => a - b);
console.log(arr); //[1, 2, 4, 5, 7, 8];

arr.sort((a, b) => b - a);
console.log(arr); //[8, 7, 5, 4, 2, 1]

arr.sort((a, b) => 0);
console.log(arr); //[8, 7, 5, 4, 2, 1]

下面是按课程点击数由高到低排序

1
2
3
4
5
6
7
8
9
let lessons = [
{ title: "CSS3", click: 78 },
{ title: "ES6", click: 12 },
{ title: "MYSQL多表查询随意操作", click: 99 },
{ title: "Node", click: 100 },
];

let sortLessons = lessons.sort((v1, v2) => v2.click - v1.click);
console.log(sortLessons);
排序原理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Array.prototype.Sort = function (callback) {
for (let i = 0; i < this.length; i++) {
for (let j = 0; j < this.length; j++) {
let temp = 0;
if (callback(this[i], this[j]) < 0) {
temp = this[i];
this[i] = this[j];
this[j] = temp;
}
}
}
};
let arr = [1, 2, 4, 5, 3];
arr.Sort((a, b) => b - a);
console.log(arr); //[5, 4, 3, 2, 1]

循环遍历

for

根据数组长度结合for 循环来遍历数组

1
2
3
4
5
6
7
8
9
10
let lessons = [
{title: '媒体查询响应式布局',category: 'css'},
{title: 'FLEX 弹性盒模型',category: 'css'},
{title: 'MYSQL多表查询随意操作',category: 'mysql'}
];

for (let i = 0; i < lessons.length; i++) {
lessons[i] = `阿顺: ${lessons[i].title}`;
}
console.log(lessons);
forEach

forEach使函数作用在每个数组元素上,但是没有返回值

关于参数:

  • 参数1:value
  • 参数2:index
  • 参数3:arr

下面例子是截取标签的五个字符。

1
2
3
4
5
6
7
8
9
10
let lessons = [
{title: '媒体查询响应式布局',category: 'css'},
{title: 'FLEX 弹性盒模型',category: 'css'},
{title: 'MYSQL多表查询随意操作',category: 'mysql'}
];

lessons.forEach((item, index, array) => {
item.title = item.title.substr(0, 5);
});
console.log(lessons);
for/in

遍历时的 key 值为数组的索引

1
2
3
4
5
6
7
8
9
let lessons = [
{title: '媒体查询响应式布局',category: 'css'},
{title: 'FLEX 弹性盒模型',category: 'css'},
{title: 'MYSQL多表查询随意操作',category: 'mysql'}
];

for (const key in lessons) {
console.log(`标题: ${lessons[key].title}`);
}
for/of

for/in 不同的是 for/of 每次循环取其中的而不是索引。

1
2
3
4
5
6
7
8
9
10
11
12
let lessons = [
{title: '媒体查询响应式布局',category: 'css'},
{title: 'FLEX 弹性盒模型',category: 'css'},
{title: 'MYSQL多表查询随意操作',category: 'mysql'}
];

for (const item of lessons) {
console.log(`
标题: ${item.title}
栏目: ${item.category == "css" ? "前端" : "数据库"}
`);
}

迭代器

​ 使用arr.keys()、arr,values()、arr.entries()创建迭代器,然后使用.next()方法进行迭代。

keys
  • .next()迭代返回值为一个对象,包含两个属性
  • value –返回当前的index
  • done –返回当前是否迭代完毕

通过迭代对象获取索引

1
2
3
4
const as = ["ashun", "Ashun"];
const keys = as.keys();
console.log(keys.next()); //[value:0,done:false]
console.log(keys.next()); //[value:1,done:false]

使用for/of结合iterator取数组所有键。因为iterator返回的是一个可迭代对象,而for/of可以遍历可迭代对象。

1
2
3
4
5
6
7
"use strict";
const arr = ["a", "b", "c", "阿顺"];

for (const key of arr.keys()) {
console.log(key);
}
console.log(arr.keys()); //Array Iterator {}

使用while遍历

1
2
3
4
5
const arr = ["ashun", "Ashun", "Ashuntefannao.com"];

while (({ value, done } = values.keys()) && !done ) {
console.log(value);
}

values
  • .next()迭代返回值为一个对象,包含两个属性
  • value –返回当前的value
  • done –返回当前是否迭代完毕

通过迭代对象获取值

1
2
3
4
5
6
const arr = ["ashun", "Ashuntefannao.com"];

let iteratorVal = arr.values();
console.log(iteratorVal.next());
console.log(iteratorVal.next());
console.log(iteratorVal.next()); //{value: undefined, done: true}

iterator结合for/of获取数组的所有值

1
2
3
4
5
6
"use strict";
const arr = ["a", "b", "c", "阿顺"];

for (const value of arr.values()) {
console.log(value);
}

entries
  • .next()迭代返回值为一个对象,包含两个属性
  • value –值为Array包含当前的key,value
  • done –返回当前是否迭代完毕
1
2
const arr = ["a", "b", "c", "阿顺"];
console.log(arr.entries().next()); //{value: [0 , "a"], done: false}

iterator结合for/of结合解构语法,获取数组的所有键值对。

1
2
3
4
const arr = ["a", "b", "c", "阿顺"];
for (const [key, value] of arr.entries()) {
console.log(key, value);
}

解构获取内容(对象章节会详细讲解)

1
2
3
4
5
6
const as = ["ashun", "SHUN"];
const iterator = as.entries();

let {done,value: [k, v]} = iterator.next();

console.log(v);

扩展方法

every

every((val,index,arr)=>Boolean),every 接收一个callback参数,并且callback必须返回一个boolean值,判断数组中的各个元素是否符合条件。

只有当所有元素都符合条件时every返回true ; 若有一个不符合就返回false,并停止遍历。

查看班级中同学的JS成绩是否都及格

1
2
3
4
5
6
7
const user = [
{ name: "李四", js: 89 },
{ name: "马六", js: 55 },
{ name: "张三", js: 78 }
];
const resust = user.every(user => user.js >= 60);
console.log(resust);

标题的关键词检查

1
2
3
4
5
6
7
8
let words = ["阿顺", "Ashun", "烦恼"];
let title = "阿顺特烦恼渴望没有烦恼";

let state = words.every(function (item, index, array) {
return title.indexOf(item) >= 0;
});

if (state == false) console.log("标题必须包含所有关键词");

some

some((val,index,arr)=>Boolean)some在使用格式上与every相同。但是两个方法的意义不同。

当数组中有一个元素符合条件时就返回true,并且停止遍历。

下面是使用 some 检测规则关键词的示例,如果匹配到一个词就提示违规。

1
2
3
4
5
6
7
8
let words = ['阿顺', 'Ashun', '烦恼'];
let title = '阿顺特烦恼渴望没有烦恼'

let state = words.some(function (item, index, array) {
return title.indexOf(item) >= 0;
});

if (state) console.log('标题含有违规关键词');

filter

filter((val,index,arr)=>Boolean),filter也接受一个callback,并且callback必须返回boolean值,通过这个boolean,过滤出符合条件的元素。

下面是使用filter获取所有的普通用户。

1
2
3
4
5
6
7
8
9
let users = [
{ name: "阿顺", type: "Controller" },
{ name: "李四 ", type: "user" },
{ name: "王五", type: "user" },
];

let ordinary = users.filter((val, index, arr) => val.type == "user");
console.log(ordinary);
//[ {name: "李四 ", type: "user"}, {name: "王五 ", type: "user"}]

我们来写一个剔除元素的方法来加深些技术

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Filter(arr, callback) {
let result = [];
arr.forEach((val, index, arr) => {
!callback(val, index, arr) && result.push(val);
});
return result;
}
const user = [
{ name: "李四", js: 89 },
{ name: "马六", js: 55 },
{ name: "张三", js: 78 },
];
console.log(Filter(user, (val, index, arr) => val.js > 60));
//[{ name: "马六", js: 55 }]

map

在使用形式上与forEach相同,都能够遍历Array

forEAch的不同点:

  • map forEach
    返回一个新数组 无返回值
    虽然能够访问到原数组的数据,但是这些都是新的存储空间值为非引用类型时,每次遍历时,必须返回一个值,作为对应位置的元素,若不返回,则对应的元素为undefined。 能够直接操作原数组的各个元素

Array的元素为 非引用类型 数据时,map操作返回的数组与原Array没有任何关系,无论是整个数组,还是数组的各个元素,都是新的内存空间。

1
2
3
4
5
6
7
8
const user = ["ashun", "Ashun", "SHUN"];

let newUser = user.map((val) => {
return val = "ASHUN";
});

console.log(user); // ["ashun", "Ashun", "SHUN"]
console.log(newUser);//["ASHUN", "ASHUN", "ASHUN"]

Array的元素为 引用类型 数据时,若每次返回的是原Array对应元素的内存地址,则map操作返回的数组,整体是仍是一个新的内存地址,但是由于对引用类型数据操作并返回,则会影响原数组的对应元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//返回原Array引用类型元素的内存地址
const user = [
{ name: "李四", js: 89 },
{ name: "马六", js: 55 },
{ name: "张三", js: 78 },
];
let newUsers = user.map((v) => {
v.js = 100;
return v;
});

console.log(newUsers);
console.log(user);
/*
[ { name: "李四", js: 100 },
{ name: "马六", js: 100 },
{ name: "张三", js: 100 } ]
*/

定义新变量,直接赋值,也是相同的内存地址

1
2
3
4
5
6
7
8
........
let newUsers = user.map((v) => {
let newValue = v; //直接赋值,与上面代码没区别。
newValue.js = 100;
return newValue;
});
console.log(user);
console.log(newUsers);

解决:可以进行浅拷贝,只是赋值其值,而不共享内存地址。【后续在Object章节会详细介绍】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
........
let newUsers = user.map((v) => {
let newValue = { ...v }; //浅拷贝
newValue.js = 100;
return newValue;
});
console.log(user);
/*
[ { name: "李四", js: 89 },
{ name: "马六", js: 55 },
{ name: "张三", js: 78 } ]
*/
console.log(newUsers);
/*
[ { name: "李四", js: 100 },
{ name: "马六", js: 100 },
{ name: "张三", js: 100 } ]
*/

reduce

使用 reducereduceRight 函数可以迭代数组的所有元素,reduce 从前开始 reduceRight 从后面开始。下面通过函数计算课程点击数的和。

第一个参数是执行函数,第二个参数为初始值

  • 传入第二个参数时将所有元素循环一遍,第二个参数为pre的初始值。
  • 不传第二个参数时从cur从第二个元素开始循环,则pre的初始值为第一个元素。

函数参数说明如下

参数 说明
prev 上次调用回调函数返回的结果
cur 当前的元素值
index 当前的索引
array 原数组

统计元素出现的次数

1
2
3
4
5
6
function countArrayELem(array, elem) {
return array.reduce((total, cur) => (total += cur == elem ? 1 : 0), 0);
}

let numbers = [1, 2, 3, 1, 5];
console.log(countArrayELem(numbers, 1)); //2

取数组中的最大值

1
2
3
4
5
6
7
function arrayMax(array) {
return array.reduce(
(max, elem) => (max > elem ? max : elem)
, array[0]);
}

console.log(arrayMax([1, 3, 2, 9]));

取价格最高的商品

1
2
3
4
5
6
7
8
9
10
11
12
let cart = [
{ name: "iphone", price: 12000 },
{ name: "imac", price: 25000 },
{ name: "ipad", price: 3600 }
];

function maxPrice(array) {
return array.reduce(
(goods, elem) => (goods.price > elem.price ? goods : elem)
,array[0]);
}
console.log(maxPrice(cart));

计算购物车中的商品总价

1
2
3
4
5
6
7
8
9
10
let cart = [
{ name: "iphone", price: 12000 },
{ name: "imac", price: 25000 },
{ name: "ipad", price: 3600 }
];

const total = cart.reduce(
(total, goods) => total += goods.price
, 0);
console.log(total); //40600

获取价格超过1万的商品名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let goods = [
{ name: "iphone", price: 12000 },
{ name: "imac", price: 25000 },
{ name: "ipad", price: 3600 }
];

function getNameByPrice(array, price) {
return array.reduce((goods, elem) => {
if (elem.price > price) {
goods.push(elem);
}
return goods;
}, []).map(elem => elem.name);
}
console.table(getNameByPrice(goods, 10000));

使用 reduce 实现数组去重

1
2
3
4
5
6
7
8
let arr = [1, 2, 6, 2, 1];
let filterArr = arr.reduce((pre, cur, index, array) => {
if (pre.includes(cur) === false) {
pre = [...pre, cur];
}
return pre;
}, [])
console.log(filterArr); // [1,2,6]
动画实例

Array-reduce.gif
1
2
3
<body>
<div>Ashuntefannao</div>
</body>
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
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

div {
text-align: center;
font-size: 30px;
}
span {
color: rebeccapurple;
font-weight: bold;
}
.active {
display: inline-block;
animation: active 0.8s 2;
letter-spacing: 0.4rem;
}
@keyframes active {
25% {
color: pink;
transform: scale(1.2);
}
40% {
color: #f1c40f;
transform: scale(1.5);
}
50% {
color: red;
transform: scale(2);
}
60% {
color: #e67e22;
transform: scale(1.5);
}
80% {
color: pink;
transform: scale(1.2);
}
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 <script>
let div = document.querySelector("div");
let text = div.innerText;
[...text].reduce((pre, val) => {
pre == 0 && (div.innerHTML = "");

let span = document.createElement("span");
span.innerText = val;
div.append(span);

span.addEventListener("mouseenter", (e) => {
e.target.classList.add("active");
});
span.addEventListener("animationend", (e) => {
e.target.classList.remove("active");
});
}, 0);
</script>