JavaScript从入门到放弃 第四步
1. new Array() 创建数组
缺点:当参数只有一个的时候创建为你填写的数字的长度,内容为undefined的数组
new Array(1,2,3)
arr => [1,2,3]
// 可以简写省略new
Array(1,2,3)
Array(2)
new Array(2)
arr => [empty x 2] 实际每项内容为undefined相当于 [undefined, undefined]
2. Array.of() 创建数组
优点:解决上面方法的弊端
Array.of()可以把一组参数转换为数组。替代es5之前的方法 Array.prototype.slice.call(arguments)
接收一组参数,创建数组
1.
Array.of(2)
arr => [2]
2.
Array.of('a');
arr => ['a']
3.
Array.of(1,2,3)
arr => [1,2,3]
3. Array.from()
// 将第一个参数有length的属性转为数组,比如字符串,伪数组,数组,arguments等,第二个参数为回调函数(callback)
// 返回值为数组
1./*因为str有length属性*/
const str = 'abcd'
Array.from(str)
arr => ['a', 'b', 'c', 'd']
2./*对象没有length属性不能解析返回的是个空数组*/
const o = {
name: 's',
age: 18
}
Array.from(o)
arr => []
3./*同样对象没有length属性不能解析返回的是个空数组*/
const o2 = {
0: 's',
1: 18
}
Array.from(o2);
arr => []
4./*对象有length属性,解析length长度就会,返回为length的值的数组,但是属性不是iterator*/
const o3 = {
name: 's',
age: 18,
length: 2
}
Array.from(o3);
arr => [undefied, undefined]; // 返回长度为o3.length,值为undefined的数组
5./*但是这样,对象有length属性并且属性值为索引值,可以被解析*/
const obj = {
0: 'aaa',
1: 'bbb',
2: 'ccc',
length: 3
}
Array.from(obj);
arr => ["aaa", "bbb", "ccc"]
6.
const obj = {
name: 'xiaoming',
1: 18,
length: 2
}
console.dir(Array.from(obj));
[undefined, 18] // 首先根据length属性的值,来创建长度为length的数组,然后数组的第一项(索引为0),去找以0为属性取填充,如果没有则为undefined,如果有取其值,然后再找,以1为属性的值,作为数组的第二项(索引为1),其实也就是:数组内每一项的值,是根据数组每一项的索引值,去对象中找是否有对应的索引值属性,如果有取其值,没有取undefined
7. 第二个参数,作用类似数组的map方法,用来对每一个元素进行处理,将处理后的值放入返回的数组中
const obj = {
name: 'xiaoming',
1: 18,
length: 2
}
let newObj = Array.from(obj, item => item || 'zcy');
["zcy", 18]
console.dir(Array.from(obj)); // 不会改变原数组
8.第三个参数,类似与map的第二个参数,与this绑定
const obj = {
name: 'xiaoming',
1: 18,
length: 2
}
let newObj = Array.from(obj, function(item) {
console.log(this);
return item || this.age;
}, { age: 19 });
// [19, 18]
# 注意: 此处函数如果写箭头函数,那么this就是window而不是 { age: 19 } 这个对象,所以如果使用传入的this就不能使用箭头函数
9.实现浅拷贝(传入一组数组)
let arr = [1,2,3,{},4];
arr2 = Array.from(arr);
10.将迭代器转为数组
转为迭代器的数组方法,values(),keys(),entries();
let arr = [2,2,4,6,1];
Array.from(arr.values()); // [2, 2, 4, 6, 1]
Array.from(arr.keys()); // [0, 1, 2, 3, 4]
Array.from(arr.entries()); // [[0, 2],[1, 2],[2, 4],[3, 6],[4, 1]]
其实我们可以使用for...of直接遍历迭代器后面会讲
4. Array.isArray() 检测是否为数组
/*检测数组是不是数组*/
const arr = [];
Array.isArray(arr);
=> true
const obj = {};
Array.isArray(obj);
=> false
5. 将数组转换为字符串的方法
1. toString() 方法
const arr = [1, 2, 3];
const str = arr.toString();
typeof str
str => "1,2,3"
"string"
2. String() 方法
const arr2 = [4, 5, 6];
const str2 = String(arr2);
typeof str2
str => "4,5,6"
"string"
3. join() 方法
const arr3 = [7, 8, 9];
const str3 = arr3.join('-');
str3 => "7-8-9"
6. 将字符串转换为数组的方法
1./**需要传入根据什么字符分割数组**/
let str = "zcy";
let arr = str.split(""); /*根据空格分割为数组*/
arr => ['z', 'c', 'y']
2.
let str = "zcy";
let arr = str.split(); /*直接将字符串转换为数组(不管字符串有没有符号)*/
arr => ['zcy']
3. 使用扩展运算符
let str = "zcy";
let strArr = [...str]; // ["z", "c", "y"] 与split不传参数结果是一样的
4. 使用Array.from()
let str = "zcy";
let strArr =Array.from(str); // ["z", "c", "y"] 与split不传参数结果是一样的
7.【 ... 】展开运算符
扩展运算符适合展开有iterable接口的,例如字符串,arguments,NodeList(DOM节点),数组等 例如[...str],但是对象没有iterable也可以展开来进行对象的混入
1.数组的展开运算符
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [...arr1, ...arr2];
改变arr3不会改变arr2和arr1
console.table(arr3);
2.函数参数的展开运算符
// 数组的参数不一定时
// 【注意】这里用...args,在ES6中叫做不定参数,和arguments的效果类似,把传入的所有参数,作为一个array赋值给args
// 可以这样理解,当...args在变量的位置时,args就是一个数组,吸收所有参数。当...args在值的位置,就是展开数组中的值,打散。
// 定义一个求和的函数
function sum (...args) {
console.log(args); // [1,2,3]
return args.reduce((pre, cur) => {
return pre + cur;
}, 0)
}
sum(1,2,3)
3. 字符串展开
let str = 'abcd';
[...str] // ["a", "b", "c", "d"]
4. NodeList(DOM节点)展开
let NodeList = document.querySelectorAll('div');
[...NodeList] // [div#oneGoogleBar, div#oneGoogleBarEndOfBody] 百度首页可查看
5. 使用展开运算符进行对象的混入,不能进行转换为数组
let obj1 = { name: 'sb', age: 2 };
let obj2 = { sex: 'w' };
let obj3 = {
...obj1,
...obj2
}
8. 遍历dom节点伪数组
<div> aaa </div>
<div> bbb </div>
const divs = document.querySelectorAll('div'); // 获取到的是dom元素的伪数组不能使用数组的遍历方法 除forEach 有兴趣的话 可以查看原型 看看有哪些方法
1. // 借用数组的map()方法
Array.prototype.map.call(divs, item => {
console.log(item);
})
2. // 借用数组的map()方法
[].map.call(divs, item => {
console.log(item);
})
3.
Array.from(divs).map(item => {
console.log(item);
})
4.
// NodeList 自身有forEach但没有map方法 转为数组可以用Array.from
[...divs].map(item => {
console.log(item)
})
9. 数组的解构赋值
数组的解构就是右侧数组的值,平均分配给左侧变量
1.以往的赋值
const arr = ['zcy',18];
const name = arr[0];
const age = arr[1];
2.解构赋值
const arr = ['zcy',18];
const [name, age] = arr;
3.使用展开运算符当变量(右边数值,比左侧变量多可以用...语法全部接收右侧的值)
const arr = ['zcy', 18, '男'];
const [name, ...args] = arr;
name => 'zcy'
args => [18, '男'];
4.当变量数量大于值数量(右边数值,比左侧变量少,如果没设置默认值少的用undefined填补)
const arr = ['zcy'];
const [name, age] = arr;
name => 'zcy'
age => undefined;
5.当变量没值,可以给变量设置默认值
const arr = ['zcy'];
const [name, age = 18] = arr;
name => 'zcy'
age => 18
6.当变量有值,还设置默认值的话,优先取赋值的值
const arr = ['zcy', 19];
const [name, age = 18] = arr;
name => 'zcy'
age => 19
10. 数组的添加和删除方法
栈方法:
ECMAScript 给数组提供几个方法,让它看起来像是另外一种数据结构。数组对象可以像栈一样, 也就是一种限制插入和删除项的数据结构。栈是一种后进先出(LIFO,Last-In-First-Out)的结构,也就 是最近添加的项先被删除。数据项的插入(称为推入,push)和删除(称为弹出,pop)只在栈的一个 地方发生,即栈顶。ECMAScript 数组提供了 push()和 pop()方法,以实现类似栈的行为。
栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)
1. push()方法
### 向数组末尾添加元素
1.利用数组长度向数组末尾添加元素
const arr = [1, 2, 3];
arr[arr.length] = 4;
arr => [1, 2, 3, 4]
2.利用数组的push()方法向数组末尾添加元素【push()方法的参数可以为多个】
const arr = [1, 2, 3];
arr.push(4); // push()方法返回值为数组的长度 【4】可以用变量去接收
const arrLength = arr.push(4);
arrLength => 4;
arr => [1, 2, 3, 4]
3.利用数组的push()方法与展开运算符向数组末尾添加多个元素
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
arr1.push(...arr2); // 此处是将arr2数组的值展开
arr1.push(4, 5, 6); // 相当于这样
arr1.push(...arr2,7,8) // 那同样也可以这样
arr => [1, 2, 3, 4, 5, 6, 7, 8];
2. pop()方法
### 删除数组末尾元素
const arr = [1, 2, 3];
arr.pop();
const arrItem = arr.pop(); // pop()方法返回值为删除的元素 【3】
arrItem => 3;
arr => [1, 2]
队列方法:
就像栈是以 LIFO 形式限制访问的数据结构一样,队列以先进先出(FIFO,First-In-First-Out)形式 限制访问。队列在列表末尾添加数据,但从列表开头获取数据。因为有了在数据末尾添加数据的 push() 方法,所以要模拟队列就差一个从数组开头取得数据的方法了。这个数组方法叫 shift(),它会删除数 组的第一项并返回它,然后数组长度减 1。使用 shift()和 push(),可以把数组当成队列来使用:
3. unshift()方法
### 向数组头部添加元素
1.向数组头部添加一个元素
const arr = [1, 2, 3];
arr.unshift(0);
const arrLength = arr.unshift(0); // unshift()方法返回值为数组长度
arrLength => 4;
arr => [0, 1, 2, 3]
2.向数组头部添加多个元素
const arr = [1, 2, 3];
arr.unshift(-1, 0);
const arrLength = arr.unshift(0); // unshift()方法返回值为数组长度
arrLength => 5;
arr => [-1, 0, 1, 2, 3]
3.利用数组的unshift()方法与展开运算符向数组头部添加多个元素
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
arr2.unshift(...arr1); // 此处是将arr2数组的值展开
arr1.unshift(1, 2, 3); // 相当于这样
arr1.unshift(-1,...arr2); // 那同样也可以这样
4. shift()方法
### 删除数组头部元素 arr.shift();
const arr = [1, 2, 3];
const arrItem = arr.shift(); // shift()方法返回值为删除的元素 【1】
arrItem => 1;
arr => [2, 3]
5. 总结:
数组的添加方法push,unshift方法返回值为数组的长度。
数组的删除方法shift,pop方法返回值为删除的元素
11. fill()数组填充
const arr = Array(6); // [empty × 6]
arr.fill('1'); // 使用1填充上面的数组
arr => [1, 1, 1, 1, 1, 1]
arr.fill(3, 2); // 使用值为3填充上面数组,从index为2的元素开始填充包括2
arr => [1, 1, 3, 3, 3, 3]
arr.fill(3, 2, 3); // 使用值为3填充上面数组,从index为2的元素开始填充(包括2)到截至到index为3不包括3
arr => [1, 1, 3, 1, 1, 1]
12. slice()数组的截取方法
### 不改变原数组
### slice: 切; 割; (v)
const arr = [1, 2, 3, 4, 5, 6];
1.// 当没有参数的时候,代表不截取,返回原组的一个副本(是浅拷贝哦,如果数组每一项都是基本数据类型,可以看作深拷贝,但是数组至少一项为引用类型,那么是浅拷贝哦)
arr.slice()
=> [1, 2, 3, 4, 5, 6]
2.//当传入一个参数代表从哪个位置截取(包括那个位置)
arr.slice(2) // 从下标值为2的位置开始截取
=> [3, 4, 5, 6];
3.//当传入两个参数代表从哪个位置截取(包括那个位置)截取到哪个位置(不包括后者)
arr.slice(2, 4)
=> [3, 4]
13. splice()数组添加截取方法
### 改变原数组
### 向/从数组中添加/删除项目,然后返回被删除的项目。
### splice: 胶接,粘接 (v)
### 返回值为删除的数组,如果未删除 则返回空数组
array.splice(index,howmany,item1,.....,itemX)
index 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany 必需。要删除的项目数量。如果设置为 0,则不会删除项目。
item1, ..., itemX 可选。向数组添加的新项目。
1.删除数组
const arr = [1, 2, 3, 4, 5];
arr2 = arr.splice(0, 3); // 截取数组
arr = [4, 5];
arr2 = [1, 2, 3];
2. 删除并新增
const arr = [1, 2, 3, 4, 5];
arr2 = arr.splice(0, 3, 'zcy'); // 截取数组
arr = ['zcy',4, 5];
arr2 = [1, 2, 3];
3.替换
const arr = [1, 2, 3, 4, 5];
arr2 = arr.splice(2, 1, 'zcy'); // 截取数组
arr = [1, 2, "zcy", 4, 5];
arr2 = [3];
splice应用的例子
// 移动数组中一个元素的位置到另一个位置的函数
function move (arr, from, to) {
// 如果传入的不是数组return
if(!Array.isArray(arr)) {
return;
}
// 判断传入的下标是否为其他类型如果传入不是number类型那么return
if(typeof from !== 'number' && typeof to !== 'number') {
return;
}
// 判断传入的下标是否为负数,如果为负数return
if(from < 0 || to < 0) {
return;
}
// 判断传入的下标超过数组的长度,如果超过return
if(from > arr.length || to > arr.length) {
return;
}
// 不能改变原数组所以我们要创建一个新数组, 对新数组操作
const tempArr = [...arr];
const item = tempArr.splice(from, 1); // 返回来的是截取一位数组
tempArr.splice(to, 0, ...item);
return tempArr;
}
const arr = [1,2,3,4,5];
move(arr,1,4); // 数组的第一个索引和第三个索引的数进行置换
14. 清空数组
let arr = [1,2,3];
let hd = arr;
1.
arr = [] // 会新开辟一个为空数组内存地址,并指向arr,并不是清空原先的数组,arr和hd引入的不是同一地址 赋值null undefined会有同样的效果
hd => [1,2,3]
arr => []
2.
arr.length = 0; // 不会新开辟一个为空数组内存地址,而是清空原先的数组,arr和hd引入的还是同一地址数组都为空了
hd => []
arr => []
3.
arr.splice(0, arr.length);
arr => []
4.
while(hd.pop()); // 解释一下 因为 删除成功会返回删除的元素 但是如果是一个空数组调用pop方法 因为没元素可删除 所以 返回undefined 当while(undefined)的时候不执行了所以就会一直删,听懂了么,听懂的打个懂字(手动滑稽)
15. join()数组转为字符串方法
join 连接,加入
split 分裂,分割
const arr = ['zcy', '18'];
const str = arr.join('/'); // 可以不加分隔符,也可以随意加分隔符
str => zcy/18
// 字符串转为数组
const str = 'zcy-18'
const arr = str.split('-'); // 以什么形式分割为数组,不传参数默认是以点空格作为分隔符
arr => ['zcy', '18'];
16. concat()数组拼接方法
concat()方法可以在现有数组全部元素基础上创建一个新数组。它首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组。如果传入一个或多个数组,则 concat()会把这些数组的每一项都添加到结果数组。如果参数不是数组,则直接把它们添加到结果数组末尾。
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
1.
const arr3 = arr1.concat(arr2); // 不会改变元素组
arr3 => [1, 2, 3, 4, 5, 6];
arr1 => [1, 2, 3];
arr2 => [4, 5, 6];
//我们更多的时候使用【...】语法
2.
arr3 = [...arr1, ...arr2];
3.浅复制数组
let copyArr = arr1.concat(); // [1, 2, 3];
4.
let copyArr = arr1.concat(4); // [1, 2, 3, 4]
17. copyWithin()
// 方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。
array.copyWithin(index, start, end);
// 会改变改变元素组
index 必需。从该位置开始替换数据
start 可选。从哪个位置开始复制数据
end 可选。停止复制位置 (默认为 array.length)。如果为负值,表示倒数。不包括它
const fruits = ["Banana", "Orange", "Apple", "Mango"];
1.
fruits.copyWithin(2, 0); // 从下标为0开始复制,如果没有结束位置复制到数组最后一项,将复制到元素,从下标为2的位置开始复制
fruits => ['Banana', 'Orange', 'Banana', 'Orange']
2.
fruits.copyWithin(2,1,2);
fruits => ['Banana', 'Orange', 'Orange', 'Mango']
解释一下 要不然很多人不是很懂,第一个参数2就是代表我们从原数组fruits[2]的值开始替换,而替换的内容是什么呢 是第二个参数1 fruits[1],和第三个参数2,fruits[2]这之间的值,包括开始的值,不包括结束的值,如果 替换的内容有多个 那么就替换多个 直到替换到多个完成
18. 查找数组元素的方法
1. indexOf()方法
arr.indexOf(searchvalue,from); // 字符串也有此方法
searchvalue 必需需检索的数组值。
from 可选参数。开始检索的位置,取值是 0 到 arr.length - 1。
// 从左往右开始查询,返回查找到的下标值,如果没有查到返回【-1】
// 区分大小写,区分数字与字符串,严格类型的查询。
const arr = [1,2,3,4,1];
arr.indexOf(2);
=> 1 // (返回的是首次出现的下标值) 如果查找不到返回-1
arr.indexOf(1,2); // 从下标为2的位置开始查
=> 4
arr.indexOf(1,-1);
=> 4
arr.indexOf(1,-2);
=> 4
arr.indexOf(1,-3);
=> 4
arr.indexOf(1,-4);
=> 4
// 总结:个人认为当使用indexOf第二个参数为负数不生效,因为下标为负数代表从右侧查询与indexOf从左侧开始查相反故不生效
2. lastIndexOf()方法
arr.lastIndexOf(searchvalue,from); // 字符串也有此方法
searchvalue 必需需检索的数组值。
from 可选参数。开始检索的位置,取值是 0 到 arr.length - 1。
// 从右往左开始查询,返回查找到的下标值,如果没有查到返回【-1】
// 区分大小写,区分数字与字符串,严格类型的查询。
const arr = [1,2,3,4,1];
arr.lastIndexOf(1)
=> 4
arr.lastIndexOf(1,0); // 从0开始查
3. includes()方法
arr.includes(value); // 字符串也有方法
// 返回boolean值
// includes实现原理
const arr = [1,2,3,4,1];
function includes(arr, el) {
for(value of arr) {
if(value === el) {
return true
}
}
return false;
}
arr.includes(1);
=> true
arr.includes(5);
=> false
const arr = [{ name: 'zcy' }, { name: 'xm' }, { name: 'sm' }];
arr.includes({name: 'zcy'});
=> false
// 引用类型比较的时候,是比较内存地址
4. find()方法
find() 方法返回为true的数组的 第一个元素的值。
当数组中的元素在测试条件时返回 true 时, find() 返回符合条件的元素,之后的值不会再调用执行函数。
如果没有符合条件的元素返回 undefined
## 注意: find() 对于空数组,函数是不会执行的。
## 注意: find() 并没有改变数组的原始值。
const arr = [1,2,3,4,5,6,2];
1.
arr.find(el => {
return el === 1; // 当el === 1的时候return true 把true对应的值返回
})
=> 1
2.
arr.find(el => {
return el === 2; // 由于有两个2所以只会返回第一个就近原则
})
=> 2
// 继续说上面例子
const arr = [{ name: 'zcy' }, { name: 'xm' }, { name: 'sm' }];
arr.find(item => {
return item.name === 'zcy'
});
=> {name: 'zcy'}
// 引用类型比较的时候,是比较内存地址
5. findIndex()方法
findIndex()与find()方法类似
findIndex方法()返回的是值所对应的下标值。
// 继续拿上面例子来说
const arr = [{ name: 'zcy' }, { name: 'xm' }, { name: 'sm' }];
arr.findIndex(item => {
return item.name === 'zcy'
});
=> 0 // 返回的是下标值
const arr = [{ name: 'zcy' }, { name: 'xm' }, { name: 'sm' }, { name: 'zcy' }];
arr.findIndex(item => {
return item.name === 'zcy'
});
=> 0 // 返回的是第一个满足条件元素的下标值所以是0不是3
19. 数组排序sort()方法
const arr = [2,1,3,6,4,5]
// arr1 = [1,2];
// arr2 = [2,1];
例如a等于1,b等于2,
a-b = 1-2为负数那么从小到大排列,
b-a = 2-1为正数那么从大到小排列
1.// 为负数从小到大 a-b为负数(会改变原数组)
arr1 = arr.sort((a,b) => {
return a - b;
})
arr1 => [1, 2, 3, 4, 5, 6]
2.// 为正数从大到小 b-a为正数(会改变原数组)
arr.sort((a,b) => {
return b - a;
})
arr => [6, 5, 4, 3, 2, 1]
例子:根据商品价格从小到大排序
const arr = [{ name: '短裙', price: 100 }, { name: 'jk', price: 99 }, { name: 'ipad', price: 12000 }]
arr.sort((a,b) => {
return a.price - b.price;
})
arr => (3) [{name: "jk", price: 99}, {name: "短裙", price: 100}, {name: "ipad", price: 12000}]
## sort方法原理
const arr = [2, 1, 3, 6, 4, 5];
// 这样写的是从小到大排序
function sort (arr) {
for(const x in arr) {
for(const y in arr) {
console.log(arr[x])
if(arr[x] < arr[y]) {
const temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
console.log(arr)
}
}
}
return arr;
}
// 那么如何进行改造像我们sort方法那样呢
function sort(a, b) {
return a - b;
}
function sort (arr,callback) {
for(const x in arr) {
for(const y in arr) {
if(callback(arr[x] , arr[y]) < 0) {
const temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
}
return arr;
}
1.
sort(arr, function(a, b) {
return a-b;
});
2.
sort(arr, (a, b) => a-b);
20.数组的循环方法
1. for循环
let arr = [{ name: 'zcy' }, { name: 'xm' }, { name: 'sm' }];
for(let i = 0; i < arr.length; i++) {
arr[i].name = `${arr[i].name}最帅`
}
arr => arr => [
{name: "zcy最帅"},
{name: "xm最帅"},
{name: "sm最帅"}
]
# 注意for循环还可以遍历dom数组
const list = document.querySelectorAll('div')
for(let i = 0; i < list.length; i++) {
list[i].style.background = 'pink'
};
2. for... in循环
let arr = [{ name: 'zcy' }, { name: 'xm' }, { name: 'sm' }];
// i为下标值
for(let i in arr) {
arr[i].name = `${arr[i].name}最帅`;
}
arr => [
{name: "zcy最帅"},
{name: "xm最帅"},
{name: "sm最帅"}
]
# 注意不能遍历dom伪数组
# 如果想遍历dom数组,那么需要使用Array.from()或者【...】转为数组才可以遍历
const list = document.querySelectorAll('div')
for (let value in Array.from(list)) {
Array.from[value].style.background = 'pink';
}
3. for...of循环
let arr = [{ name: 'zcy' }, { name: 'xm' }, { name: 'sm' }];
// value为遍历的每一项
for(let value of arr) {
value.name = `${value.name}最帅`;
}
arr => [
{name: "zcy最帅"},
{name: "xm最帅"},
{name: "sm最帅"}
]
// 其实是改变数组中的对象,由于对象是引用类型,所以可以修改原数组,
// 但原数组的每一项都是,值类型那不不会对原数组有任何改变
我们来看下个例子
let arr = [1,2,3];
for(let value of arr) {
value = '帅'; // 试图修改数组中的每一项
console.log(value); // '帅'
}
arr => [1,2,3]
// 结果是没修改成功,因为不是引用类型,会新开辟一块空间赋值给value变量这样就没有修改原数组,可以理解为【副本】
# 注意不能遍历dom数组
# 如果想遍历dom数组,那么需要使用Array.from()或者【...】转为数组才可以遍历
const list = document.querySelectorAll('div')
for (let value of Array.from(list)) {
value.style.background = 'pink';
}
4. forEach()循环
let arr = [{ name: 'zcy' }, { name: 'xm' }, { name: 'sm' }];
item 为遍历数组的每一项
index 为遍历每一项的下标值
arr 为遍历的数组
arr.forEach((item, index, arr)) {
item.name = `${item.name}最帅`;
}
// 注意:同样也是只能改变引用类型
arr => [
{name: "zcy最帅"},
{name: "xm最帅"},
{name: "sm最帅"}
]
# 注意forEach还可以遍历dom数组
5. 迭代iterator方法遍历数组
const arr = [{ name: 'zcy' }, { name: 'xm' }, { name: 'sm' }];
# 可迭代的对象就可以使用next()方法
const values = arr.values(); // 返回的是一个迭代对象,取的是值
const keys = arr.keys(); //返回的是一个迭代对象,取的是索引
let { value, done } = values.next(); // 从迭代对象中取出值
console.log(values.next());
console.log(values.next());
# 当使用values(),value是值
# 当使用keys(),value是索引
# done代表的是是否迭代完成,false代表没有迭代完成
const entries = arr.entries(); // 返回的是一个迭代对象 是keys和values的综合方法
console.log(entries.next()); // 执行一边的话会只打印第一次迭代的对象
let { done, value: [index, item] } = entries.next()
=> { done: false, value: [1, { name: 'zcy' }] } // 1是索引 { name: 'zcy' }是值
// for...of遍历迭代器
for (const [key, value] of arr.entries()) {
console.log(key, value);
}
const arr = [{ name: 'zcy' }, { name: 'xm' }, { name: 'sm' }];
const values = arr.values();
while(({ value, done } = values.next()) && done === false) {
console.log(value); // 也能遍历数组
}
21. 数组的some与every方法
1. some()
// some 返回结果是个boolean值
// some 接收一个回调函数作为参数
// 回调函数有三个参数,分别为数组循环的每一项,索引值,和数组
// 代表数组中只要有一项满足条件就返回true,否则返回false
const arr = [
{ name: 'zcy', achievement: '100' },
{ name: 'sm', achievement: '89' },
{ name: 'xm', achievement: '59' }
];
`假如我想要查询全班是否有未及格的人`
arr.some(function(item, index, arr) {
return item.achievement < 60; // 只要有一个满足返回的条件那么就返回true
});
简写为:
arr.some(item => item.achievement < 60);
=> true
2. every()
// every 返回结果是个boolean值
// every 接收一个回调函数作为参数
// 回调函数有三个参数,分别为数组循环的每一项,索引值,和数组
// 代表数组的每一项都满足条件就返回true,否则返回false
const arr = [
{ name: 'zcy', achievement: '100' },
{ name: 'sm', achievement: '89' },
{ name: 'xm', achievement: '59' }
];
`假如我想要查询全班考试是否都未及格`
arr.every(function(item, index, arr) {
return item.achievement < 60; // 每一项都满足条件,那么就返回true
});
简写为:
arr.every(item => item.achievement < 60);
=> false
22. 数组的filter()方法
// filter 返回结果是一个数组,不会改变原数组,但是返回的引用类型数组是浅拷贝,值类型的数组是深拷贝
// filter 接收一个回调函数作为参数
// 回调函数有三个参数,分别为数组循环的每一项,索引值,和数组
// 返回数组满足条件的每一项组成的新数组
const arr = [
{ name: 'zcy', achievement: 100 },
{ name: 'sm', achievement: 100 },
{ name: 'xm', achievement: 59 }
];
arr.filter(item => {
return item.achievement === 100;
})
arr => [
{ name: 'zcy', achievement: 100 },
{ name: 'sm', achievement: 100 }
];
23. 数组的map()方法
// map 返回结果是一个数组,不会改变原数组,但是返回的引用类型数组是浅拷贝,值类型的数组是深拷贝
// map 接收一个回调函数作为参数
// 回调函数有三个参数,分别为数组循环的每一项,索引值,和数组
// 返回数组return每一项组成的新数组
1.数组的每一项都为,值类型的数组
const arr = [1, 2, 3, 4, 5];
const newArr = arr.map((item, index, arr) => {
return false // 返回什么新数组就是什么
})
newArr => [false, false, false, false, false];
arr => [1, 2, 3, 4, 5]; // 不会改变原数组
const newArr = arr.map((item, index, arr) => {
return `LimitLess${item}` // 返回什么新数组就是什么
})
newArr => ["LimitLess1", "LimitLess2", "LimitLess3", "LimitLess4", "LimitLess5"]
arr => [1, 2, 3, 4, 5]; // 不会改变原数组
24. 数组的reduce()方法
// reduce 返回结果是一个数组,不会改变原数组,但是返回的引用类型数组是浅拷贝,值类型的数组是深拷贝
// reduce 接收一个回调函数作为参数
// 回调函数有四个参数,分别为数组循环的初始值,下一项的值,索引值,和数组
// 返回数组满足条件的每一项组成的新数组
const arr = [1,2,3,4,4,4,5];
1.
// 如果没有给pre初始值,那么默认pre的值为数组的第一项,之后pre为函数执行返回的值
// next 为数组的第二项
arr.reduce((pre, next, index, arr) => {
console.log(pre); // 1
console.log(next); // 2
})
2.
// 如果给pre初始值,那么下一次pre值为函数执行后返回的值
// next 为数组的第一项
arr.reduce((pre, next, index, arr) => {
console.log(pre); // []
console.log(next); // 1
},[]) // 给默认值可以为任意值 0 null undefined [] {}
例子1:判断一个元素在数组中出现的次数
function total (arr, el) {
return arr.reduce((total, next) => {
total += next === el ? 1 : 0
return total;
}, 0)
}
total(arr,4);
=> 3
例子2:获取元素中的最大值
function max (arr) {
return arr.reduce((pre,next) => {
return pre > next ? pre : next;
})
}
max(arr);
=> 5
当然只是练习reduce如果要查询数组中最大值更简单的方法是
Math.max(...arr)
例子3:求和
function sum (arr) {
return arr.reduce((pre,next) => {
return pre += next;
})
}
sum(arr);
=> 23
例子4:数组去重
const newArr = arr.reduce((pre,cur) => {
pre.includes(cur) ? '' : pre.push(cur);
return pre;
},[])
=> [1, 2, 3, 4, 5]
例子5:数组对象去重
const arr = [
{name: "zcy最帅"},
{name: "xm最帅"},
{name: "sm最帅"},
{name: "zcy最帅"},
{name: "xm最帅"},
{name: "sm最帅"}
]
// 1.第一种对象数组去重方法(根据某个字段去重)
const obj = {};
const newArr = arr.reduce((pre,next) => {
obj[next.name] ? '' : obj[next.name] = pre.push(next);
return pre;
}, [])
newArr => [
{name: "zcy最帅"},
{name: "xm最帅"},
{name: "sm最帅"}
]
aSelectedtAreaId = arr.map(item => item.name)
const aMultipleSelectionArea = []; // 筛选出选中的部门数据
arr.reduce((pre, cur) => {
console.log(pre);
console.log(cur);
pre.includes(cur.name) ? '' : aMultipleSelectionArea.push(cur);
return pre;
}, aSelectedtAreaId);
// 2.第二种对象数组去重方法
const newArr = arr.reduce((pre, next) => {
// 没找到返回undefined,找到返回对象
let isFind = !!pre.find(item => item.name === next.name);
if(!isFind) {
pre.push(next);
}
return pre;
}, [])
newArr => [
{name: "zcy最帅"},
{name: "xm最帅"},
{name: "sm最帅"}
]
总结:使用遍历数组的时候,会把数组中的值赋值给item,如果是值类型,不会改变原数组,如果事对象引用类型,那么会改变原数组
25. reverse()数组的翻转方法
// 会改变原数组
const arr = [1, 2, 3, 4, 5];
arr.reverse();
arr =>[5, 4, 3, 2, 1]
26. 数组的flat()方法
1. flat()方法作用就是数组降维
2. 利用flat()方法的特性来去除数组的空项
3. 不会改变原数组
const arr1 = [1, 2, [3, 4]];
arr1.flat();
=> [1, 2, 3, 4]
const arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
=> [1, 2, 3, 4, [5, 6]]
const arr3 = [1, 2, [3, 4, [5, 6]]];
arr.flat(2);
=> [1, 2, 3, 4, 5, 6]
//使用 Infinity 作为深度,展开任意深度的嵌套数组
arr3.flat(Infinity);
=> [1, 2, 3, 4, 5, 6]
//去除空项
var arr4 = [1, 2, , 4, 5];
arr4.flat();
=> [1, 2, 4, 5]; // 但是不能去除undefined,null
27. flatMap()
flatMap()方法对原数组的每个成员执行一个函数,相当于执行Array.prototype.map(),然后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组。
// 相当于 [[2, 4], [3, 6], [4, 8]].flat()
[[2, 4], [3, 6], [4, 8]].flatMap((item) => {
return item;
})
// [2, 4, 3, 6, 4, 8]
注意:flatMap()只能展开一层数组。
28. 排序算法
1.选择排序
// 步骤:
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。重复,直到所有元素均排序完毕。
// 代码实现
function selectionSort(arr) {
for(let i = 0; i < arr.length;i++) {
let minIndex = i; // 默认将数组的第0项当作最小值
for(let j = i + 1; j < arr.length; j++) {
if(arr[j] < arr[minIndex]) {
minIndex = j;
}
}
let temp = arr[i]; // 存第一项
arr[i] = arr[minIndex]; // 第一项改为最小项
arr[minIndex] = temp; // 第一项给默认值
}
return arr;
}
let arr = [6,9,4,1,0,7];
selectionSort(arr);
// 进阶封装
// 封装一个从小到大的排序方法
function sort1 (a,b) {
return a - b;
}
// 封装一个从大到小的排序方法
function sort2 (a,b) {
return b - a;
}
let arr = [6,9,4,1,0,7];
selectionSort(arr, sort1);
function selectionSort(arr,sort) {
for(let i = 0; i < arr.length;i++) {
let minIndex = i; // 默认将数组的第0项当作最小值
for(let j = i + 1; j < arr.length; j++) {
if(sort(arr[j], arr[minIndex]) < 0){
minIndex = j;
}
}
let temp = arr[i]; // 存第一项
arr[i] = arr[minIndex]; // 第一项改为最小项
arr[minIndex] = temp; // 第一项给默认值
}
return arr;
}
- 冒泡排序(Bubble Sort)
比较两个相邻的元素,如果第一个比第二个大,就交换它们两个。对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;针对所有的元素重复以上的步骤,除了最后一个。重复步骤1~3,直到排序完成。【这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。】
1. 代码实现
function bubbleSort(arr){
for(let i = 0; i < arr.length; i++) {
// 第一次只需要 交换 arr.length -1 -0 次
// 第二次只需要 交换 arr.length -1 -1 次
// 第三次只需要 交换 arr.length -1 -2 次
// 所以 arr.length -1 - i
// 第二层for循环每次循环选出一个最大(小)值,所以需要两次for循环外层控制次数,内层控制排序
for(let j = 0; j < arr.length -1 - i; j++) {
if(arr[j] > arr[j + 1]) {
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
let arr = [6,9,4,1,0,7];
bubbleSort(arr);
2. 封装改进
function sort1(a, b) {
return a - b
} // 实现从小到大的函数
function sort2(a, b) {
return b - a
} // 实现从大到小的函数
function bubbleSort(arr, func){
for(let i = 0; i < arr.length; i++) {
for(let j = 0; j < arr.length -1 - i; j++) {
if(func(arr[j], arr[j + 1]) > 0) {
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
let arr = [6,9,4,1,0,7];
bubbleSort(arr, sort1);
3.插入排序
实现思路:
1.从数组的第二个数据开始往前比较,即一开始用第二个数和他前面的一个比较,如果 符合条件(比前面的大或者小,自定义),则让他们交换位置。
2.然后再用第三个数和第二个比较,符合则交换,但是此处还得继续往前比较,比如有 5个数8,15,20,45, 17,17比45小,需要交换,但是17也比20小,也要交换,当不需 要和15交换以后,说明也不需要和15前面的数据比较了,肯定不需要交换,因为前 面的数据都是有序的。
3.重复步骤二,一直到数据全都排完。
// 代码实现
let arr = [8,15,20,45,17];
function insertionSort() {
for(let i = 0; i< arr.length; i++) {
for(let j = 0; j< arr.length; j++){
if(arr[i] > arr[j]) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
insertionSort(arr);
// 那么如何进行改造像我们sort方法那样呢
function sort(a, b) {
return a - b;
}
function sort (arr,callback) {
for(const x in arr) {
for(const y in arr) {
if(callback(arr[x] , arr[y]) < 0) {
const temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
}
return arr;
}
我对JavaScript如初恋,JavaScript虐我千百遍。

浙公网安备 33010602011771号