红宝书学习笔记
第一章: 字符串操作方法
第二章: 数组之创建数组
第三章: 数组之数组方法
文章目录
- 红宝书学习笔记
- 前言
- 一、检测数组 Array.isArray()
- 二、迭代器方法 keys()、 values()、entries()
- 三、复制 copyWithin() 和 填充 fill()
- 四、转换方法 toLocalString() 、toString() 、valueOf() 、join()
- 五、栈方法 队列方法 push() pop() shift() unshift()
- 六、排序方法 reverse() 、sort()
- 七、操作方法 concat() 、 slice() 、splice()
- 八、搜索和位置方法 indexOf() 、lastIndexOf() 、includes()、find() 、findIndex()
- 严格相等 indexOf() 、lastIndexOf() 、includes()
- 九、迭代方法 every() 、filter() 、forEach() 、map() 、some()
- 十、归并方法 reduce() 、reduceRight()
前言
前一篇介绍了创建数组的各种方式,本篇主要介绍数组方法。
一、检测数组 Array.isArray()
判断一个对象是不是数组,我们通常使用的是 value instanceof Array
去判断,但是这有一个大前提是,只有一个网页(因而只有一个全局作用域)。如果网页里有多个框架,可能设计两个不同的全局执行上下文,因此就会有两个不同版本的 Array 构造函数。如果要把数组从一个框架传给另一个框架,则这个数组的构造函数将有别于在第二个框架内本地创建的数组。
为解决这个问题,ECMAScript提供了Array.isArray()
方法。
这个方法的目的就是确定一个值是否为数组,而不用管它是在哪个全局执行上下文中创建的。
二、迭代器方法 keys()、 values()、entries()
在ES6中,Array原型上暴露了3个用于检索数组内容的方法: keys()、 values()、entries()
。
keys()
返回数组索引的迭代器,
values()
返回数组元素的迭代器,
entries()
返回索引/值对的迭代器。
const a = ["foo","bar","baz","qux"];
// 因为这些方法都返回迭代器,所以可以将他们的内容通过Array.from() 直接转换为数组实例
const aKeys = Array.from(a.keys());
const aValues = Array.from(a.values());
const aEntries = Array.from(a.entries());
console.log(aKeys); // [0, 1, 2, 3]
console.log(aValues); // ["foo", "bar", "baz", "qux"]
console.log(aEntries); // [[0, "foo"], [1, "bar"], [2, "baz"], [3, "qux"]]
三、复制 copyWithin() 和 填充 fill()
这两种方法都需要指定既有数组实例上的一个范围,包含 开始索引,不包含 结束索引。使用这个方法不回改变数组的大小。
fill()
使用fill()
方法可以向一个已有的数组中插入全部或部分相同的值。
- 开始索引用于指定开始填充的位置。
- 如果不提供结束索引,将一直填充到数组末尾
- 负值索引从数组末尾开始计算,也可以换算为 arr.length + 负值
例:
const zeroes = [0, 0, 0, 0, 0];
// 用5填充整个数组
zeroes.fill(5);
console.log(zeroes); // [5, 5, 5, 5, 5]
zeroes.fill(0); // 重置
// 用6 填充索引值大于等于3的元素
zeroes.fill(6, 3);
console.log(zeroes); // [0, 0, 0, 6, 6]
zeroes.fill(0); // 重置
// 用7 填充索引值大于等于1且小于3的元素
zeroes.fill(7, 1, 3);
console.log(zeroes); // [0, 7, 7, 0, 0]
zeroes.fill(0); // 重置
// 用8 填充索引值大于等于1且小于4的元素
// -4 + 5(zeroes.length) = 1
// -1 + 5(zeroes.length) = 4
zeroes.fill(8, -4, -1);
console.log(zeroes); // [0, 8, 8, 8, 0]
zeroes.fill(0); // 重置
fill() 静默忽略超出数组边界、零长度及方向相反的索引范围
zeroes.fill(1, -10, -6); // 索引过低,忽略
zeroes.fill(1, 6, 10); // 索引过高,忽略
zeroes.fill(1, 5, 3); // 索引反向,忽略
zeroes.fill(2, 4, 10); // 索引部分有效,执行有效部分,忽略无效部分 输出 : [0, 0, 0, 2, 2]
copyWithin()
copyWithin()
按照指定范围浅复制数组中的部分内容,然后将他们插入到指定索引开始的位置。开始索引和结束索引与 fill()
计算方法相同。
let ints,
rest = () => ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
rest();
// 从ints中复制索引 0 开始的内容,插入到索引 5 开始的位置。
ints.copyWithin(5);
console.log(ints); // [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
rest();
// 从ints 中复制索引 5 开始的内容,插入到索引 0 开始的位置
ints.copyWithin(0, 5);
console.log(ints); // [5,6,7,8,9,5,6,7,8,9]
rest();
// 从ints中复制索引 0 开始到索引 3 结束的内容,插入到索引4 开始的位置
ints.copyWithin(4, 0, 3);
console.log(ints); // [0, 1, 2, 3, 0, 1, 2, 7, 8, 9]
reset();
// 支持负值索引
ints.copyWithin(-4, -7, -3);
console.log(ints); //[0, 1, 2, 3, 4, 5, 3, 4, 5, 6]
reset();
copyWithin() 静默忽略超出数组边界、零长度及方向相反的索引范围
ints.copyWithin(1, -15, -12); // 索引过低,忽略
ints.copyWithin(1, 12, 15); // 索引过高,忽略
ints.copyWithin(1, 4, 2); // 索引反向,忽略
ints.copyWithin(2, 7, 10); // 索引部分有效,执行有效部分,忽略无效部分 输出 : [0, 1, 7, 8, 9, 5, 6, 7, 8, 9]
四、转换方法 toLocalString() 、toString() 、valueOf() 、join()
valueOf()
返回数组本身。
toString()
返回由数组中每个值的等效字符串拼接而成的以逗号分隔的字符串。
let colors = ["red", "pink", "blue", "green" ];
console.log(colors.toString()); // red,pink,blue,green // 显式调用
console.log(colors.valueOf()); // red,pink,blue,green // 显式调用
alert(colors); // red,pink,blue,green // 由于alert 期待返回字符串,在后台调用数组的toString() 方法
toLocalString()
也可能返回相同的结果。但是也不一定。因为调用它时,调用的时数组的 toLocalString()
方法,而不是 toString()
方法。
方法定义不同时,返回结果不一定相同。
join()
方法可以定义不同的分隔符
let colors = ["red", "pink", "blue", "green" ];
alert(colors.join(",")); // red,pink,blue,green
alert(colors.join("||")); // red||pink||blue||green
alert(colors.join()); // red,pink,blue,green
五、栈方法 队列方法 push() pop() shift() unshift()
栈方法 push() + pop()
ECMAScript给数组提供几个方法,让它看起来像是另外一种数据结构,数组对象可以像栈一样,也就是一种限制插入和删除项的数据结构。
栈是一种后进先出的结构,也就是最近添加的项先被删除。
push()
方法接收任意数量的参数,并将它们添加到数组末尾,返回数组的最新长度。
pop()
方法用于删除数组的最后一项,同时减少数组的length值,返回被删除的项。
let colors = new Array(); // 创建一个数组
let count = colors.push("red", "green"); // 推入两项
alert(count); // 2
count = colors.push("blue"); // 再推入一项
alert(count); // 3
let item = colors.pop(); // 取得最后一项
alert(item); // blue
alert(colors.length); // 2
队列方法 push() + shift()
队列以先进先出的形式限制访问。 队列在列表末尾添加数据,但从列表开头获取数据。
shift()
方法删除数组的第一项并返回它,同时数组长度减 1 。
let colors = new Array(); // 创建一个数组
let count = colors.push("red", "green"); // 推入两项
alert(count); // 2
count = colors.push("blue"); // 再推入一项
alert(count); // 3
let item = colors.shift(); // 取得第一项
alert(item); // red
alert(colors.length); // 2
unshift()
方法接收任意数量的参数,并将它们添加到数组头部,返回数组的最新长度。
使用unshift()
和 pop()
,可以在相反方向上模拟队列。
六、排序方法 reverse() 、sort()
reverse()
方法用于将数组元素反向排列
let values = [1, 2, 3, 4, 5];
alert(values.reverse()); // 5,4,3,2,1
sort()
用于重新排序,默认情况下按照升序重新排列数组元素,即最小的值在前面,最大的值在后面。
但是,sort() 会在每一项上调用String() 转型函数,然后比较字符串来决定顺序,即使元素都是数值,也会转换为字符串进行比较排序,因此会出现以下情况:
let values = [1, 2, 10, 15];
values.sort();
alert(values); // 1,10,15,2
因为字符串“10”“15”会排在字符串“2”前面。很明显,这在很多情况下都不是最合适的。因此,sort() 方法可以接收一个比较函数,用于判断哪个值应该排在前面。
function compare(value1, value2) {
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}
let values = [1, 10, 2, 15];
values.sort(compare);
alert(values); // 1,2,10,15
如果希望产生降序效果,只需要把返回值交换一下即可
function compare(value1, value2) {
if (value1 < value2) {
return 1;
} else if (value1 > value2) {
return -1;
} else {
return 0;
}
}
let values = [1, 10, 2, 15];
values.sort(compare);
alert(values); // 15,10,2,1
可以简写为箭头函数
let values = [1, 10, 2, 15];
values.sort((a, b) => a < b ? 1 : a > b ? -1 : 0);
alert(values); // 15,10,2,1
如果数组的元素是数值,或者他valueOf() 返回数值的对象,这个比较函数可以写得更简单,因为这时可以用第二个值减去第一个值:
function compare(value1, value2) {
return value2 - value1;
}
七、操作方法 concat() 、 slice() 、splice()
concat()
concat() 方法可以在现有数组全部元素基础上创建一个新数组。他会先创建一个当前数组的副本,再把它的参数添加到副本末尾,最后返回这个新构建的数组。
- 原始数组保持不变,返回一个新数组。
- 如果参数是一个或多个数组,每一项都添加到末尾。
- 如果不是数组,直接添加到数组末尾。
let colors = ["red", "green", "blue"];
let colors2 = colors.concat("yellow", ["pink", "black"]);
console.log(colors); // ['red', 'green', 'blue']
console.log(colors2); // ['red', 'green', 'blue', 'yellow', 'pink', 'black']
slice()
slice() 方法用于创建一个包含原有数组中一个或多个元素的新数组。
- 接收一个或两个参数:返回元素的开始索引和结束索引。
- 如果只有一个参数,返回开始索引到末尾的所有元素。
- 不影响原始数组。
let colors = ["red", "green", "blue", "pink", "black"];
let colors2 = colors.slice(1);
let colors3 = colors.slice(1, 4);
console.log(colors2); // ['green', 'blue', 'pink', 'black']
console.log(colors3); // ['green', 'blue', 'pink']
splice()
splice() 主要目的是在数组中间插入元素,但有3种不同的方式使用这个方法。
删除。
需要给splice() 传入两个参数:要删除的第一个元素的位置、要删除的元素的数量。
插入
需要给splice() 传入至少三个参数:开始位置、要删除的元素数量为0、要插入的元素。
替换
需要给splice() 传入至少三个参数: 开始位置、要删除元素的数量、任意的多个元素。
- 始终返回一个新数组,这个数组包含被删除的元素,如果没有删除元素,则返回空数组。
放在一起对比:
let colors = ["red", "green", "blue"];
let removed = colors.splice(0, 1); // 删除第一项
alert(colors); // green,blue
alert(removed); // red
removed = colors.splice(1, 0, "yellow", "orange"); // 在位置1 插入两个元素
alert(colors); // green,yellow,orange,blue
alert(removed); // 空数组
removed = colors.splice(1, 1, "red", "pink"); // 在位置1 删除一个元素,然后插入两个元素
alert(colors); // green,red,pink,orange,blue
alert(removed); // yellow
八、搜索和位置方法 indexOf() 、lastIndexOf() 、includes()、find() 、findIndex()
严格相等 indexOf() 、lastIndexOf() 、includes()
相同点
- 都接收两个参数,第一个参数表示要查找的元素,第二个参数为可选的起始搜索位置。
- 判断相等时,会使用 === 进行比较,即 两者必须严格相等。
不同点
- indexOf 从数组第一项开始向后搜索,返回结果为 位置下标或 -1(没搜到);
- lastIndexOf 从数组最后一项开始向前搜索,返回结果为 位置下标 或 -1(没搜到);
- includes 从数组第一项开始向后搜索,返回结果为布尔值,表示是否找到至少一个与指定元素匹配的项
let numbers = [1,2,3,4,5,4,3,2,1]
alert(numbers.indexOf(4)); // 3
alert(numbers.lastIndxOf(4)); // 5
alert(numbers.includes(4)); // true
alert(numbers.indexOf(4, 4)); // 5
alert(numbers.lastIndxOf(4, 4)); // 3
alert(numbers.includes(4, 7)); // false
let person = { name: "Bob" };
let people = [{ name: "Bob" } ];
let people1 = [person];
alert(people.indexOf(person)); // -1
alert(people1.indexOf(person)); // 0
alert(people.includes(person)); // false
alert(people1.includes(person)); // true
断言函数 find() 、findIndex()
ECMAScript 也允许按照定义的断言函数搜索数组,每个索引都会调用这个函数。
断言函数接收三个参数:元素、索引、数组本身。 断言函数返回真值,表示是否匹配。
find() 和 findIndex() 使用了断言函数。
这两个方法都是从数组的最小索引开始
两个方法接收的第一个参数表示需要匹配的元素;第二个可选参数用于指定断言函数内部this的值
找到匹配项后,两个方法都不再继续搜索
find 返回第一个匹配的元素
findIndex返回第一个匹配元素的索引
const people = [
{
name: "Bob",
age: 18,
},
{
name: "Jack",
age: 20,
},
];
console.log(people.find((element, index, array) => element.age < 19));
// {name: 'Bob', age: 18}
console.log(people.findIndex((element, index, array) => element.age < 19));
// 0
九、迭代方法 every() 、filter() 、forEach() 、map() 、some()
every()
:对数组每一项都运行传入的函数,如果对每一项函数都返回true,则这个方法返回 true;
filter()
:对数组每一项都运行传入的函数,函数返回true的项会组成数组之后返回;
forEach()
:对数组每一项都运行传入的函数,没有返回值;
map()
:对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组;
some()
:对数组每一项都运行传入的函数,如果有一项函数返回true,则这个方法返回 true;
共同点:
这些方法都不改变原数组。
let numbers = [1,2,3,4,5,4,3,2,1];
// every 用于确定是否所有元素都符合指定条件
let everyResult = numbers.every((item,index,array) => item > 2);
console.log(everyResult); // false
// some用于确定是否至少含有一个符合条件的元素
let someResult = numbers.some((item,index,array) => item > 2);
console.log(someResult); //true
// filter用于筛选符合某些条件的元素
let filterResult = numbers.filter((item,index,array) => item > 2) ;
alert(filterResult); // 3,4,5,4,3
// map方法非常适合生成一个与原数组元素一一对应的新数组
let mapResult = numbers.map((item,index,array) => item*2);
alert(mapResult); // 2,4,6,8,10,8,6,4,2
// forEach 不返回内容,执行一些操作
numbers.forEach((item,index,array) => {
// 执行某些操作
})
十、归并方法 reduce() 、reduceRight()
这两个方法都会迭代数组的所有项,并在此基础上构建一个最终返回值。
reduce方法从第一项开始遍历到最后一项
reduceRight方法从最后一项开始遍历到第一项
这两个方法都接收两个参数:归并函数、可选的初始值;
- 归并函数接收四个参数:上一个归并值、当前项、当前项的索引、数组本身
// 可以使用reduce 方法执行累加数组中所有数值的操作
let values = [1, 2, 3, 4, 5];
let sum = values.reduce((prev, cur, idnex, array) => prev + cur);
alert(sum); // 15