数组类型 数组是多个变量值的集合,数组是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.of
与 new 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"]
栈和队列 利用push
、shift
能够模拟队列操作(先进先出),利用unshift
、shift
能够模拟栈操作,操作栈顶(后进先出)。
小总结 :
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 findIndex
与 find
的区别是返回索引值。其余用法相同。
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 使用 reduce
与 reduceRight
函数可以迭代数组的所有元素,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]
动画实例
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>