JS Array专项复习2 ——数组的实例方法
其实资深开发者都懂,不懂也知道查,或者GPT,但是有的时候面试官可能会问数组的实例方法这种问题,另外将数组实例方法巧记于心在开发中可以省去查找咨询GPT的时间**(毕竟当你懂了之后,问GPT的效率也会变高)**。🏳️🌈标识的是我工作中经常用到的
3. 数组实例方法
3.1 Array.prototype.at()🏳️
at 在这里翻译过来就是在(位置) 像小学英语中的at home(在家)一样 ,本质上就是找数组在索引位置上的元素,只不过你不仅可以正着找也可以倒着找
3.1.1 语法
at()
方法接收一个整数值并返回该索引对应的元素,允许正数和负数。负整数从数组中的最后一个元素开始倒数。
at(index)
- 1
index
要返回的数组元素的索引(从零开始),会被转换为整数。负数索引从数组末尾开始计数——如果 index < 0
,则会访问 index + array.length
位置的元素。。
返回值
返回数组中与给定索引匹配的元素。如果 index < -array.length
或 index >= array.length
,则总是返回 undefined
,而不会尝试访问相应的属性。
3.1.2 示例
1. 返回数组中的最后一个值
// 数组及数组元素
const cart = ["apple", "banana", "pear"];
// 一个函数,用于返回给定数组的最后一个元素
function returnLast(arr) {
return arr.at(-1);
}
// 获取 'cart' 数组的最后一个元素
const item1 = returnLast(cart);
console.log(item1); // 输出:'pear'
// 在 'cart' 数组中添加一个元素
cart.push("orange");
const item2 = returnLast(cart);
console.log(item2); // 输出:'orange'
Array.from("foo");
// [ "f", "o", "o" ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
2. 在非数组对象中调用at()
at()
方法读取 this
的 length
属性并计算需要访问的索引。 也就是在类数组对象中使用也是可以的。
const arrayLike = {
length: 2,
0: "a",
1: "b",
};
console.log(Array.prototype.at.call(arrayLike, -1)); // "b"
- 1
- 2
- 3
- 4
- 5
- 6
3.2 Array.prototype.concat()🏳️
concat 就是concatenate的缩写,翻译过来就是连接,这个函数在很多语言中都有,记不住这个单词可以去看里 concatenate | “concatenate” 的词源、“concatenate” 的起源和意思 - etymonline
3.2.1 语法
concat()
方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
concat()
concat(value0)
concat(value0, value1)
concat(value0, value1, /* … ,*/ valueN)
- 1
- 2
- 3
- 4
valueN
valueN
是数组或者是一个值,valueN
将被合并到一个新的数组中。如果省略了所有 valueN
参数,则 concat
会返回现存数组的一个浅拷贝。
返回值
一个新的数组
3.2.2 示例
1. 连接两个数组
const letters = ["a", "b", "c"];
const numbers = [1, 2, 3];
const alphaNumeric = letters.concat(numbers);
console.log(alphaNumeric);
// results in ['a', 'b', 'c', 1, 2, 3]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
2. 连接三个数组
at()
方法读取 this
的 length
属性并计算需要访问的索引。
const num1 = [1, 2, 3];
const num2 = [4, 5, 6];
const num3 = [7, 8, 9];
const numbers = num1.concat(num2, num3);
console.log(numbers);
// results in [1, 2, 3, 4, 5, 6, 7, 8, 9]
- 1
- 2
- 3
- 4
- 5
- 6
3. 将值合并到数组
const letters = ["a", "b", "c"];
const alphaNumeric = letters.concat(1, [2, 3]);
console.log(alphaNumeric);
// results in ['a', 'b', 'c', 1, 2, 3]
- 1
- 2
- 3
- 4
4. 合并嵌套数组
const num1 = [[1]];
const num2 = [2, [3]];
const numbers = num1.concat(num2);
console.log(numbers);
// [[1], 2, [3]]
// 修改 num1 的第一个元素
num1[0].push(4);
console.log(numbers);
// [[1, 4], 2, [3]]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
5. 类数组对象中使用concat()
concat
默认情况下不会将类数组对象视作数组——仅在 Symbol.isConcatSpreadable
被设置为真值(例如,true
)时才会将类数组对象视作数组。
const obj1 = { 0: 1, 1: 2, 2: 3, length: 3 };
const obj2 = { 0: 1, 1: 2, 2: 3, length: 3, [Symbol.isConcatSpreadable]: true };//加个这玩意
console.log([0].concat(obj1, obj2));
// [ 0, { '0': 1, '1': 2, '2': 3, length: 3 }, 1, 2, 3 ]
- 1
- 2
- 3
- 4
3.3 Array.prototype.copyWithin()🏳️
copy: 复制 within 在…之内 翻译过来就是在内部复制
3.3.1 语法
copyWithin()
方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。
copyWithin(target)
copyWithin(target, start)
copyWithin(target, start, end) //三个参数均为数字
- 1
- 2
- 3
target
将要被替换/覆盖的索引
- 负索引将从数组末尾开始计数——如果
target < 0
,则实际是target + array.length
。 - 如果
target < -array.length
,则使用0
。 - 如果
target >= array.length
,则不会拷贝任何内容。 - 如果
target
位于start
之后,则复制只会持续到array.length
结束(换句话说,copyWithin()
永远不会扩展数组)。
start
默认为0
内部复制的起始索引
- 负索引将从数组末尾开始计数——如果
start < 0
,则实际是start + array.length
。 - 如果省略
start
或start < -array.length
,则默认为0
。 - 如果
start >= array.length
,则不会拷贝任何内容。
end
默认为数组长度arr.length
内部复制的结束索引
copyWithin
将会拷贝到该位置,但不包括 end
这个位置的元素。
- 负索引将从数组末尾开始计数——如果
end < 0
,则实际是end + array.length
。 - 如果
end < -array.length
,则使用0
。 - 如果省略
end
或end >= array.length
,则默认为array.length
,这将导致直到数组末尾的所有元素都被复制。 - 如果
end
位于start
之前,则不会拷贝任何内容。
返回值
改变后的数组。
3.3.2 示例
1. 使用copywithin
console.log([1, 2, 3, 4, 5].copyWithin(-2));
// [1, 2, 3, 1, 2]
console.log([1, 2, 3, 4, 5].copyWithin(0, 3));
// [4, 5, 3, 4, 5]
console.log([1, 2, 3, 4, 5].copyWithin(0, 3, 4));
// [4, 2, 3, 4, 5]
console.log([1, 2, 3, 4, 5].copyWithin(-2, -3, -1));
// [1, 2, 3, 3, 4]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
2. 在稀疏数组上使用
copywithin将会保留空槽
console.log([1, , 3].copyWithin(2, 1, 2)); // [1, empty, empty]
- 1
3. 在非数组对象中使用copywithin
copyWithin()
方法读取 this
的 length
属性,然后操作所涉及的整数索引。
const arrayLike = {
length: 5,
3: 1,
};
console.log(Array.prototype.copyWithin.call(arrayLike, 0, 3));
// { '0': 1, '3': 1, length: 5 }
console.log(Array.prototype.copyWithin.call(arrayLike, 3, 1));
// { '0': 1, length: 5 }
// '3' 属性被删除,因为在复制的源中是一个空槽
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.4 Array.prototype.entries()🏳️
entries: 这个词的意思是“条目”或“项”。可以联想成“每个条目都有一个编号(索引)和内容(值)”。
3.4.1 语法
Array.prototype.entries() 是 JavaScript 中数组的一个方法,用于返回一个新的数组迭代器对象,该对象包含数组中每个元素的键值对(索引和值)
entries()
- 1
- 2
返回值
一个新的可迭代对象。
3.4.2 示例
1. 迭代元素索引和元素值
const arr = ['apple', 'banana', 'cherry'];
const iterator = arr.entries();
for (const [index, value] of iterator) {
console.log(index, value);
}
// 0 apple
// 1 banana
// 2 cherry
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2. 使用for…of循环
const array = ["a", "b", "c"];
const arrayEntries = array.entries();
for (const element of arrayEntries) {
console.log(element);
}
// [0, 'a']
// [1, 'b']
// [2, 'c']
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3. 迭代稀疏数组
entries()
将访问空槽,就像它们是 undefined
一样。
for (const element of [, "a"].entries()) {
console.log(element);
}
// [0, undefined]
// [1, 'a']
- 1
- 2
- 3
- 4
- 5
4. 在非数组对象中调用entries()
entries()
方法读取 this
的 length
属性,然后访问每个整数索引。
const arrayLike = {
length: 3,
0: "a",
1: "b",
2: "c",
};
for (const entry of Array.prototype.entries.call(arrayLike)) {
console.log(entry);
}
// [ 0, 'a' ]
// [ 1, 'b' ]
// [ 2, 'c' ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
3.5 Array.prototype.every()🏳️
every 所有 所有都符合要求
它还有一个好兄弟 some 后面就不介绍了 语法解构和它一样 只不过是只要有一个符合要求就行
3.5.1 语法
every()
方法测试一个数组内的所有元素是否都能通过指定函数的测试。它返回一个布尔值。如果在数组中每个元素使得提供的函数返回 true,则返回 true;否则返回 false。
some()
方法测试数组中是否至少有一个元素通过了由提供的函数实现的测试。如果在数组中找到一个元素使得提供的函数返回 true,则返回 true;否则返回 false。
every(callbackFn)
every(callbackFn, thisArg)
- 1
- 2
callbackFn
为数组中的每个元素执行的函数。它应该返回一个真值以指示元素通过测试,否则返回一个假值。该函数被调用时将传入以下参数:
-
element
数组中当前正在处理的元素。
-
index
正在处理的元素在数组中的索引。
-
array
调用了
every()
的数组本身。
thisArg
执行 callbackFn
时用作 this
的值。参见迭代方法。
返回值
如果 callbackFn
为每个数组元素返回真值,则为 true
。否则为 false
。
3.5.2 示例
1. 检查所有数组元素的大小
function isBigEnough(element, index, array) {
return element >= 10;
}
[12, 5, 8, 130, 44].every(isBigEnough); // false
[12, 54, 18, 130, 44].every(isBigEnough); // true
- 1
- 2
- 3
- 4
- 5
- 6
2. 检查一个数组是否是另一个数组的子集
const isSubset = (array1, array2) =>
array2.every((element) => array1.includes(element));
console.log(isSubset([1, 2, 3, 4, 5, 6, 7], [5, 7, 6])); // true
console.log(isSubset([1, 2, 3, 4, 5, 6, 7], [5, 8, 7])); // false
- 1
- 2
- 3
- 4
- 5
3. 在稀疏数组上使用every
every()
不会在空槽上运行它的断言函数。可以理解为跳过了
console.log([1, , 3].every((x) => x !== undefined)); // true
console.log([2, , 2].every((x) => x === 2)); // true
- 1
- 2
4. 在非数组对象上调用 every()
const arrayLike = {
length: 3,
0: "a",
1: "b",
2: "c",
};
console.log(
Array.prototype.every.call(arrayLike, (x) => typeof x === "string"),
); // true
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
3.6 Array.prototype.fill()🏳️
fill 填充 可以简单理解为给一个数值,我将start位置到end位置的所有元素都填充为value
3.6.1 语法
fill()
方法用一个固定值填充一个数组中从起始索引(默认为 0
)到终止索引(默认为 array.length
)内的全部元素。它返回修改后的数组
fill(value)
fill(value, start)
fill(value, start, end)
- 1
- 2
- 3
value
用来填充数组元素的值。注意所有数组中的元素都将是这个确定的值:如果 value
是个对象,那么数组的每一项都会引用这个元素。
start
起始索引位置 默认为0
- 负数索引从数组的末端开始计算,如果
start < 0
,则使用start + array.length
。 - 如果
start < -array.length
或start
被省略,则使用0
。 - 如果
start >= array.length
,没有索引被填充。
end
结束索引位置 默认为array.length
- 负数索引从数组的末端开始计算,如果
end < 0
,则使用end + array.length
。 - 如果
end < -array.length
,则使用0
。 - 如果
end >= array.length
或end
被省略,则使用array.length
,导致所有索引都被填充。 - 如果经标准化后,
end
的位置在start
之前或之上,没有索引被填充。
返回值
经 value
填充修改后的数组。
3.6.2 示例
1. 使用fill
console.log([1, 2, 3].fill(4)); // [4, 4, 4]
console.log([1, 2, 3].fill(4, 1)); // [1, 4, 4]
console.log([1, 2, 3].fill(4, 1, 2)); // [1, 4, 3]
console.log([1, 2, 3].fill(4, 1, 1)); // [1, 2, 3]
console.log([1, 2, 3].fill(4, 3, 3)); // [1, 2, 3]
console.log([1, 2, 3].fill(4, -3, -2)); // [4, 2, 3]
console.log([1, 2, 3].fill(4, NaN, NaN)); // [1, 2, 3]
console.log([1, 2, 3].fill(4, 3, 5)); // [1, 2, 3]
console.log(Array(3).fill(4)); // [4, 4, 4]
// 一个简单的对象,被数组的每个空槽所引用
const arr = Array(3).fill({}); // [{}, {}, {}]
arr[0].hi = "hi"; // [{ hi: "hi" }, { hi: "hi" }, { hi: "hi" }]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
2. 使用fill创建全1矩阵
const arr = new Array(3);
for (let i = 0; i < arr.length; i++) {
arr[i] = new Array(4).fill(1); // 创建一个大小为 4 的数组,填充全 1
}
arr[0][0] = 10;
console.log(arr[0][0]); // 10
console.log(arr[1][0]); // 1
console.log(arr[2][0]); // 1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3. 使用fill填充空数组
此示例演示了如何填充数组,将所有值设定为一个特定的值。无需指定 end
参数。
const tempGirls = Array(5).fill("girl", 0);
- 1
注意,数组最初为稀疏数组,没有分配索引。fill()
仍然可以填充这个数组。
4. 非数组对象上使用fill()
fill()
方法读取 this
的 length
属性,并设置从 start
到 end
的每个整数属性的值。
const arrayLike = { length: 2 };
console.log(Array.prototype.fill.call(arrayLike, 1));
// { '0': 1, '1': 1, length: 2 }
- 1
- 2
- 3
3.7 Array.prototype.filter()🏳️🌈
filter 过滤 过滤符合条件的元素 将这些元素组成一个新的数组
3.7.1 语法
filter()
方法创建给定数组一部分的浅拷贝,其包含通过所提供函数实现的测试的所有元素。
filter(callbackFn)
filter(callbackFn, thisArg)
- 1
- 2
callbackFn
为数组中的每个元素执行的函数。它应该返回一个真值以将元素保留在结果数组中,否则返回一个假值。该函数被调用时将传入以下参数
element
数组中当前正在处理的元素。
index
正在处理的元素在数组中的索引。
array
调用了 filter()
的数组本身。
thisArg
执行 callbackFn
时用作 this
的值。
返回值
返回给定数组的一部分的浅拷贝,只包含能够通过callbackFn数组的值,如果所有元素都不能通过 那么就返回空数组
3.7.2 示例
1. 筛选大于10的元素
function isBigEnough(value) {
return value >= 10;
}
const filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]
- 1
- 2
- 3
- 4
- 5
- 6
2. 找出数组中所有的素数
const array = [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
function isPrime(num) {
for (let i = 2; num > i; i++) {
if (num % i === 0) {
return false;
}
}
return num > 1;
}
console.log(array.filter(isPrime)); // [2, 3, 5, 7, 11, 13]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
3. 过滤json中的无效条目
const arr = [
{ id: 15 },
{ id: -1 },
{ id: 0 },
{ id: 3 },
{ id: 12.2 },
{},
{ id: null },
{ id: NaN },
{ id: "undefined" },
];
let invalidEntries = 0;
function filterByID(item) {
if (Number.isFinite(item.id) && item.id !== 0) {
return true;
}
invalidEntries++;
return false;
}
const arrByID = arr.filter(filterByID);
console.log("过滤后的数组\n", arrByID);
// 过滤后的数组
// [{ id: 15 }, { id: -1 }, { id: 3 }, { id: 12.2 }]
console.log("无效条目数量 =", invalidEntries);
// 无效条目数量 = 5
- 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
4. 在稀疏数组上使用 filter()
filter()
将跳过空槽。
console.log([1, , undefined].filter((x) => x === undefined)); // [undefined]
console.log([1, , undefined].filter((x) => x !== 2)); // [1, undefined]
- 1
- 2
5. 在非数组对象上使用filter()
const arrayLike = {
length: 3,
0: "a",
1: "b",
2: "c",
};
console.log(Array.prototype.filter.call(arrayLike, (x) => x <= "b"));
// [ 'a', 'b' ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.8 Array.prototype.find()🏳️🌈
find 寻找 目的就是找出元素
3.8.1 语法
find()
方法返回数组中满足提供的测试函数的第一个元素的值。否则返回undefined。它还有一个亲兄弟,Array.prototype.findLast()语法与它一模一样,只不过是返回满足测试函数的最后一个元素的值
find(callbackFn)
find(callbackFn, thisArg)
- 1
- 2
callbackFn
为数组中的每个元素执行的函数。它应该返回一个真值来表示已经找到了匹配的元素。该函数被调用时将传入以下参数:
-
element
数组中当前正在处理的元素。
-
index
正在处理的元素在数组中的索引。
-
array
调用了
find()
的数组本身。
thisArg
执行 callbackFn
时用作 this
的值
返回值
数组中第一个满足所提供测试函数的元素的值,否则返回undefined
3.8.2 示例
1. 在数组对象中通过属性进行查找
const inventory = [
{ name: "apples", quantity: 2 },
{ name: "bananas", quantity: 0 },
{ name: "cherries", quantity: 5 },
];
function isCherries(fruit) {
return fruit.name === "cherries";
}
console.log(inventory.find(isCherries));
// { name: 'cherries', quantity: 5 }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
2. 使用箭头函数和解构赋值
const inventory = [
{ name: "apples", quantity: 2 },
{ name: "bananas", quantity: 0 },
{ name: "cherries", quantity: 5 },
];
const result = inventory.find(({ name }) => name === "cherries");
console.log(result); // { name: 'cherries', quantity: 5 }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
3. 在稀疏数组上使用find()
在稀疏数组中,空槽会被访问的,并被视为 undefined
。
// 声明一个在索引 2、3 和 4 处没有元素的数组
const array = [0, 1, , , , 5, 6];
// 将会打印所有索引,而不仅仅是那些有值的非空槽
array.find((value, index) => {
console.log(`访问索引 ${index},值为 ${value}`);
});
// 访问索引 0,值为 0
// 访问索引 1,值为 1
// 访问索引 2,值为 undefined
// 访问索引 3,值为 undefined
// 访问索引 4,值为 undefined
// 访问索引 5,值为 5
// 访问索引 6,值为 6
// 打印所有索引,包括已删除的
array.find((value, index) => {
// 在第一次迭代时删除元素 5
if (index === 0) {
console.log(`删除 array[5] 的值 ${array[5]}`);
delete array[5];
}
// 即使删除了,元素 5 仍然被访问
console.log(`访问索引 ${index},值为 ${value}`);
});
// 删除值为 5 的 array[5]
// 访问索引 0,值为 0
// 访问索引 1,值为 1
// 访问索引 2,值为 undefined
// 访问索引 3,值为 undefined
// 访问索引 4,值为 undefined
// 访问索引 5,值为 undefined
// 访问索引 6,值为 6
- 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
4. 在非数组对象上使用find()
find()
方法读取 this
的 length
属性,然后访问每个整数索引。
const arrayLike = {
length: 3,
0: 2,
1: 7.3,
2: 4,
};
console.log(Array.prototype.find.call(arrayLike, (x) => !Number.isInteger(x)));
// 7.3
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.9 Array.prototype.findIndex()🏳️🌈
显而易见,find寻找,index索引 findIndex就是寻找索引
3.9.1 语法
findIndex()
方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回 -1。它还有一个亲兄弟,Array.prototype.findLastIndex()语法与它一模一样,只不过是返回满足测试函数的最后一个索引
findIndex(callbackFn)
findIndex(callbackFn, thisArg)
- 1
- 2
callbackFn
为数组中的每个元素执行的函数。它应该返回一个真值来表示已经找到了匹配的元素。该函数被调用时将传入以下参数:
-
element
数组中当前正在处理的元素。
-
index
正在处理的元素在数组中的索引。
-
array
调用了
findIndex()
的数组本身。
thisArg
执行 callbackFn
时用作 this
的值
返回值
数组中第一个满足所提供测试函数的元素的索引,否则返回-1
3.9.2 示例
1. 在数组中寻找首个素数的索引
function isPrime(element) {
if (element % 2 === 0 || element < 2) {
return false;
}
for (let factor = 3; factor <= Math.sqrt(element); factor += 2) {
if (element % factor === 0) {
return false;
}
}
return true;
}
console.log([4, 6, 8, 9, 12].findIndex(isPrime)); // -1,没有找到
console.log([4, 6, 7, 9, 12].findIndex(isPrime)); // 2(array[2] 是 7)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
2. 在稀疏数组中使用findIndex()
你可以搜索稀疏数组中的 undefined
并来获取空槽的索引。
console.log([1, , 3].findIndex((x) => x === undefined)); // 1
- 1
3. 在非数组对象中使用findIndex()
const arrayLike = {
length: 3,
0: 2,
1: 7.3,
2: 4,
};
console.log(
Array.prototype.findIndex.call(arrayLike, (x) => !Number.isInteger(x)),
); // 1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.10 Array.prototype.flat()🏳️
flat 平的 就像一个擀面杖把一个有很多层的数组给它碾平,可以传入参数深度来控制擀面杖的力度。
3.10.1 语法
flat()
方法创建一个新的数组,并根据指定深度递归地将所有子数组元素拼接到新的数组中。
flat()
flat(depth)
- 1
- 2
-
depth
指定要提取嵌套数组的结构深度,默认值为 1。
返回值
一个新的数组,其中包含拼接后的子数组元素
3.10.2 示例
1. 展平嵌套数组
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]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
const arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
2. 在稀疏数组上使用flat
flat()
方法删除数组中的空槽:(也就是说使用flat后最外层的数组不可能存在空槽,就像擀面杖擀的最外层表皮不可能有个大洞)
const arr5 = [1, 2, , 4, 5];
console.log(arr5.flat()); // [1, 2, 4, 5]
const array = [1, , 3, ["a", , "c"]];
console.log(array.flat()); // [ 1, 3, "a", "c" ]
const array2 = [1, , 3, ["a", , ["d", , "e"]]];
console.log(array2.flat()); // [ 1, 3, "a", ["d", empty, "e"] ]
console.log(array2.flat(2)); // [ 1, 3, "a", "d", "e"]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3. 非数组对象使用flat()
flat()
方法读取 this
的 length
属性,然后访问每个整数索引。如果元素不是数组,则直接将其附加到结果中。如果元素是数组,则根据 depth
参数进行展开操作。
const arrayLike = {
length: 3,
0: [1, 2],
// 嵌套的类数组对象不会被展平
1: { length: 2, 0: 3, 1: 4 },
2: 5,
};
console.log(Array.prototype.flat.call(arrayLike));
// [ 1, 2, { '0': 3, '1': 4, length: 2 }, 5 ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.11 Array.prototype.flatMap()🏳️
类似于先试用map再使用深度为1的flat
3.11.1 语法
flatMap()
方法对数组中的每个元素应用给定的回调函数,然后将结果展开一级,返回一个新数组。
它等价于在调用 map()
方法后再调用深度为 1 的 flat()
方法(arr.map(...args).flat()
),但比分别调用这两个方法稍微更高效一些。
flatMap(callbackFn)
flatMap(callbackFn, thisArg)
- 1
- 2
- 3
callbackFn
一个在数组的每个元素上执行的函数。它应该返回一个包含新数组元素的数组,或是要添加到新数组中的单个非数组值。该函数将被传入以下参数:
-
element
数组中正在处理的当前元素。
-
index
数组中正在处理的当前元素的索引。
-
array
调用
flatMap()
的当前数组。thisArg
在执行
callbackFn
时用作this
的值
返回值
一个新的数组,其中每个元素都是回调函数的结果,并且被展开一级。
替代方案
const arr = [1, 2, 3, 4];
arr.flatMap((x) => [x, x * 2]);
// 等价于
const n = arr.length;
const acc = new Array(n * 2);
for (let i = 0; i < n; i++) {
const x = arr[i];
acc[i * 2] = x;
acc[i * 2 + 1] = x * 2;
}
// [1, 2, 2, 4, 3, 6, 4, 8]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
需要注意的是,在这种特定情况下,flatMap
方法的性能比 for 循环要慢——因为需要创建临时数组并进行垃圾回收,同时返回的数组不需要经常调整大小。但是,在注重灵活性和可读性的情况下,flatMap
仍可能是正确的解决方案。
3.11.2 示例
1. map()与flatmap()
const arr1 = [1, 2, 3, 4];
arr1.map((x) => [x * 2]);
// [[2], [4], [6], [8]]
arr1.flatMap((x) => [x * 2]);
// [2, 4, 6, 8]
// 只有一层被展平
arr1.flatMap((x) => [[x * 2]]);
// [[2], [4], [6], [8]]
// 从一组句子中生成单词列表
const arr1 = ["it's Sunny in", "", "California"];
arr1.map((x) => x.split(" "));
// [["it's","Sunny","in"],[""],["California"]]
arr1.flatMap((x) => x.split(" "));
// ["it's","Sunny","in", "", "California"]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
2. 稀疏数组使用flatmap()
callbackFn
不会被源数组中的空槽调用,因为 map()
不会调用,而 flat()
将忽略返回数组中的空槽。
console.log([1, 2, , 4, 5].flatMap((x) => [x, x * 2])); // [1, 2, 2, 4, 4, 8, 5, 10]
console.log([1, 2, 3, 4].flatMap((x) => [, x * 2])); // [2, 4, 6, 8]
- 1
- 2
3. 在非数组对象中使用
flatMap()
方法读取 this
的 length
属性,然后访问每个整数索引。如果回调函数的返回值不是数组,则始终直接将其附加到结果数组的末尾。
const arrayLike = {
length: 3,
0: 1,
1: 2,
2: 3,
};
console.log(Array.prototype.flatMap.call(arrayLike, (x) => [x, x * 2]));
// [1, 2, 2, 4, 3, 6]
// 回调函数返回的类数组对象不会被展平
console.log(
Array.prototype.flatMap.call(arrayLike, (x) => ({
length: 1,
0: x,
})),
);
// [ { '0': 1, length: 1 }, { '0': 2, length: 1 }, { '0': 3, length: 1 } ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
3.12 Array.prototype.forEach()🏳️
for循环 Each 每个 对数组的每个元素执行一次给定的函数。
3.12.1 语法
forEach()
方法对数组的每个元素执行一次给定的函数。
forEach(callbackFn)
forEach(callbackFn, thisArg)
- 1
- 2
callbackFn
为数组中每个元素执行的函数。并会丢弃它的返回值。该函数被调用时将传入以下参数:
-
element
数组中正在处理的当前元素。
-
index
数组中正在处理的当前元素的索引。
-
array
调用
forEach()
的当前数组。thisArg
在执行
callbackFn
时用作this
的值
返回值
undefined
。
3.12.2 示例
1. 在稀疏数组上使用 forEach()
空槽不会执行forEach的callbackFn函数
const arraySparse = [1, 3, /* empty */, 7];
let numCallbackRuns = 0;
arraySparse.forEach((element) => {
console.log({ element });
numCallbackRuns++;
});
console.log({ numCallbackRuns });
// { element: 1 }
// { element: 3 }
// { element: 7 }
// { numCallbackRuns: 3 }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
2. 使用 thisArg
下面的代码会为每一个数组元素输出一行记录:
class Counter {
constructor() {
this.sum = 0;
this.count = 0;
}
add(array) {
// 只有函数表达式才有自己的 this 绑定
array.forEach(function countEntry(entry) {
this.sum += entry;
++this.count;
}, this);
}
}
const obj = new Counter();
obj.add([2, 5, 9]);
console.log(obj.count); // 3
console.log(obj.sum); // 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
3. 扁平化数组 (使用递归)
const flatten = (arr) => {
const result = [];
arr.forEach((item) => {
if (Array.isArray(item)) {
result.push(...flatten(item));
} else {
result.push(item);
}
});
return result;
};
// 用例
const nested = [1, 2, 3, [4, 5, [6, 7], 8, 9]];
console.log(flatten(nested)); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
4. 非数组对象上使用forEach()
forEach()
方法读取 this
的 length
属性,然后访问每个整数索引。
const arrayLike = {
length: 3,
0: 2,
1: 3,
2: 4,
};
Array.prototype.forEach.call(arrayLike, (x) => console.log(x));
// 2
// 3
// 4
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.13 Array.prototype.includes()🏳️
includes 包含嘛 本质上就是看这个数组包不包含这个元素
3.13.1 语法
includes()
方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true
,否则返回 false
。
includes(searchElement)
includes(searchElement, fromIndex)
- 1
- 2
searchElement
需要查找的值。
fromIndex
开始搜索的索引(从零开始),会转换为整数。
- 负索引从数组末尾开始计数——如果
fromIndex < 0
,那么实际使用的是fromIndex + array.length
。然而在这种情况下,数组仍然从前往后进行搜索。 - 如果
fromIndex < -array.length
或者省略fromIndex
,则使用0
,这将导致整个数组被搜索。 - 如果
fromIndex >= array.length
,则不会搜索数组并返回false
。
返回值
一个布尔值,如果在数组中(或者在 fromIndex
所指示的数组部分中,如果指定 fromIndex
的话)找到 searchElement
值,则该值为 true
。
3.13.2 示例
1. 使用includes()
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
[1, 2, NaN].includes(NaN); // true
["1", "2", "3"].includes(3); // false
- 1
- 2
- 3
- 4
- 5
- 6
2. 在稀疏数组上使用includes()
你可以在稀疏数组中搜索 undefined
,得到 true
。
console.log([1, , 3].includes(undefined)); // true
- 1
3. 在非数组对象中使用includes()
includes()
方法读取 this
的 length
属性,然后访问每个整数索引。
const arrayLike = {
length: 3,
0: 2,
1: 3,
2: 4,
};
console.log(Array.prototype.includes.call(arrayLike, 2));
// true
console.log(Array.prototype.includes.call(arrayLike, 1));
// false
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.14 Array.prototype.indexOf()🏳️
index 索引 取索引用的 也就是数组的下标
3.14.1 语法
indexOf()
方法返回数组中第一次出现给定元素的下标,如果不存在则返回 -1。
他还有一个孪生兄弟
lastIndexOf()
方法返回数组中给定元素最后一次出现的索引,如果不存在则返回 -1。该方法从 fromIndex
开始向前搜索数组。
indexOf(searchElement)
indexOf(searchElement, fromIndex)
lastIndexOf(searchElement)
lastIndexOf(searchElement, fromIndex)
- 1
- 2
- 3
- 4
searchElement
数组中要查找的元素。
fromIndex
开始搜索的索引(从零开始),会转换为整数。
- 负索引从数组末尾开始计数——如果
fromIndex < 0
,那么实际使用的是fromIndex + array.length
。然而在这种情况下,数组仍然从前往后进行搜索。 - 如果
fromIndex < -array.length
或者省略fromIndex
,则使用0
,这将导致整个数组被搜索。 - 如果
fromIndex >= array.length
,则不会搜索数组并返回false
。
返回值
首个被找到的元素在数组中的索引位置; 若没有找到则返回 -1。
3.14.2 示例
1. 使用indexOf()
const array = [2, 9, 9];
array.indexOf(2); // 0
array.indexOf(7); // -1
array.indexOf(9, 2); // 2
array.indexOf(2, -1); // -1
array.indexOf(2, -3); // 0
// 你没法使用 indexOf() 来搜索 NaN。
const array = [NaN];
array.indexOf(NaN); // -1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2. 在稀疏数组上使用indexOf()
不能使用 indexOf()
在稀疏数组中搜索空槽。
console.log([1, , 3].indexOf(undefined)); // -1
- 1
3. 在非数组对象中使用indexOf()
const arrayLike = {
length: 3,
0: 2,
1: 3,
2: 4,
};
console.log(Array.prototype.indexOf.call(arrayLike, 2));
// 0
console.log(Array.prototype.indexOf.call(arrayLike, 5));
// -1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.15 Array.prototype.join()🏳️
join 加入 将数组中的所有元素加入到一个字符串中 如果只有一个元素 那么就直接返回该元素
3.15.1 语法
join()
方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串,用逗号或指定的分隔符字符串分隔。如果数组只有一个元素,那么将返回该元素而不使用分隔符。
join()
join(separator)
- 1
- 2
separator
指定一个字符串来分隔数组的每个元素。如果需要,将分隔符转换为字符串。如果省略,数组元素用逗号(,
)分隔。如果 separator
是空字符串(""
),则所有元素之间都没有任何字符。
返回值
一个所有数组元素连接的字符串。如果 arr.length
为 0
,则返回空字符串。
3.15.2 示例
1. 使用四种方式连接字符串
const a = ["Wind", "Water", "Fire"];
a.join(); // 'Wind,Water,Fire'
a.join(", "); // 'Wind, Water, Fire'
a.join(" + "); // 'Wind + Water + Fire'
a.join(""); // 'WindWaterFire'
- 1
- 2
- 3
- 4
- 5
2. 在稀疏数组上使用join()
join()
将空槽视为 undefined
,并产生额外的分隔符:
console.log([1, , 3].join()); // '1,,3'
console.log([1, undefined, 3].join()); // '1,,3'
- 1
- 2
3. 在类数组对象中使用join()
join()
方法读取 this
的 length
属性,然后访问每个整数索引。
const arrayLike = {
length: 3,
0: 2,
1: 3,
2: 4,
};
console.log(Array.prototype.join.call(arrayLike));
// 2,3,4
console.log(Array.prototype.join.call(arrayLike, "."));
// 2.3.4
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.16 Array.prototype.keys()🏳️
keys 也就是key的集合
3.16.1 语法
keys()
方法返回一个新的数组迭代器对象,其中包含数组中每个索引的键。
keys()
- 1
返回值
一个新的可迭代迭代器对象。
3.16.2 示例
1. 基础使用
const array1 = ['a', 'b', 'c'];
const iterator = array1.keys();
for (const key of iterator) {
console.log(key);
}
// Expected output: 0
// Expected output: 1
// Expected output: 2
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
2. 在稀疏数组中使用 keys()
与 Object.keys()
只包含数组中实际存在的键不同,keys()
迭代器不会忽略缺失属性的键。
const arr = ["a", , "c"];
const sparseKeys = Object.keys(arr);
const denseKeys = [...arr.keys()];
console.log(sparseKeys); // ['0', '2']
console.log(denseKeys); // [0, 1, 2]
- 1
- 2
- 3
- 4
- 5
3. 在非数组对象上调用 keys()
const arrayLike = {
length: 3,
};
for (const entry of Array.prototype.keys.call(arrayLike)) {
console.log(entry);
}
// 0
// 1
// 2
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.17 Array.prototype.map()🏳️🌈
map 对数组的元素进行地图式的扫荡,每个元素都执行一遍函数,并把每个元素的函数返回值组成一个新的数组
3.17.1 语法
map()方法创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成。
map(callbackFn)
map(callbackFn, thisArg)
- 1
- 2
callbackFn
为数组中的每个元素执行的函数。它的返回值作为一个元素被添加为新数组中。该函数被调用时将传入以下参数:
-
element
数组中当前正在处理的元素。
-
index
正在处理的元素在数组中的索引。
-
array
调用了
map()
的数组本身。
thisArg
执行 callbackFn
时用作 this
的值。
返回值
一个新数组
3.17.2 示例
1. 求数组中每个元素的平方根
const numbers = [1, 4, 9];
const roots = numbers.map((num) => Math.sqrt(num));
// roots 现在是 [1, 2, 3]
// numbers 依旧是 [1, 4, 9]
- 1
- 2
- 3
- 4
- 5
2. 使用 map 重新格式化数组中的对象
const kvArray = [
{ key: 1, value: 10 },
{ key: 2, value: 20 },
{ key: 3, value: 30 },
];
const reformattedArray = kvArray.map(({ key, value }) => ({ [key]: value }));
console.log(reformattedArray); // [{ 1: 10 }, { 2: 20 }, { 3: 30 }]
console.log(kvArray);
// [
// { key: 1, value: 10 },
// { key: 2, value: 20 },
// { key: 3, value: 30 }
// ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
3.稀疏数组上使用map
稀疏数组在使用 map()
方法后仍然是稀疏的。空槽的索引在返回的数组中仍然为空,并且回调函数不会对它们进行调用。
console.log(
[1, , 3].map((x, index) => {
console.log(`Visit ${index}`);
return x * 2;
}),
);
// Visit 0
// Visit 2
// [2, empty, 6]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
4. 非数组对象上调用map
map()
方法读取 this
的 length
属性,然后访问每个整数索引。
const arrayLike = {
length: 3,
0: 2,
1: 3,
2: 4,
};
console.log(Array.prototype.map.call(arrayLike, (x) => x ** 2));
// [ 4, 9, 16 ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.18 Array.prototype.pop()🏳️
很多语言都实现了这个pop 丢弃最后一个元素
3.18.1 语法
pop()
方法从数组中删除最后一个元素,并返回该元素的值。此方法会更改数组的长度。
pop()
- 1
返回值
从数组中删除的元素(当数组为空时返回 undefined
)。
3.18.2 示例
1. 删除数组中的最后一个元素
const myFish = ["angel", "clown", "mandarin", "sturgeon"];
const popped = myFish.pop();
console.log(myFish); // ['angel', 'clown', 'mandarin' ]
console.log(popped); // 'sturgeon'
- 1
- 2
- 3
- 4
- 5
- 6
- 7
2. 在非数组对象上调用 pop()
pop()
方法会读取 this
上的 length
属性。如果规范化的 length 属性为 0,length
会被再次设置为 0(鉴于之前可能是负数或者 undefined
)。否则,返回并删除位于 length - 1
处的属性。
const arrayLike = {
length: 3,
unrelated: "foo",
2: 4,
};
console.log(Array.prototype.pop.call(arrayLike));
// 4
console.log(arrayLike);
// { length: 2, unrelated: 'foo' }
const plainObj = {};
// 没有 length 属性,所以长度为 0
Array.prototype.pop.call(plainObj);
console.log(plainObj);
// { length: 0 }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
3. 以类数组的方式使用对象
push
和 pop
方法是通用的,我们可以利用这一点来编写更灵活的代码——如以下示例所示。
请注意,在此示例中,我们不会创建数组来存储对象集合。相反,我们将集合存储在对象本身上,并在 Array.prototype.push
和 Array.prototype.pop
上使用 call
来欺骗这些方法,让它们认为我们正在处理一个数组。
const collection = {
length: 0,
addElements(...elements) {
// 每次添加元素时
// obj.length 都会自动增加
// 返回 push 方法的返回值,即 length 属性的新值
return [].push.call(this, ...elements);
},
removeElement() {
// 每次移除元素时
// obj.length 都会自动减少
// 返回 pop 方法的返回值,即被移除的元素
return [].pop.call(this);
},
};
collection.addElements(10, 20, 30);
console.log(collection.length); // 3
collection.removeElement();
console.log(collection.length); // 2
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
3.19 Array.prototype.push()🏳️
push推入 放入 在后面放入元素
3.19.1 语法
push()
方法将指定的元素添加到数组的末尾,并返回新的数组长度。
push()
push(element0)
push(element0, element1)
push(element0, element1, /* … ,*/ elementN)
- 1
- 2
- 3
- 4
- 5
-
elementN
添加到数组末尾的元素。
返回值
调用方法的对象的新 length
属性。
3.19.2 示例
1. 在数组中添加元素
const sports = ["soccer", "baseball"];
const total = sports.push("football", "swimming");
console.log(sports); // ['soccer', 'baseball', 'football', 'swimming']
console.log(total); // 4
- 1
- 2
- 3
- 4
- 5
- 6
2. 合并两个数组
使用展开运算符将第二个数组的所有元素添加到第一个数组中
const vegetables = ["parsnip", "potato"];
const moreVegs = ["celery", "beetroot"];
// 合并第二个数组到第一个数组中
vegetables.push(...moreVegs);
console.log(vegetables); // ['parsnip', 'potato', 'celery', 'beetroot']
- 1
- 2
- 3
- 4
- 5
- 6
- 7
3. 非数组对象上使用push()
push()
方法会读取 this
的 length
属性。然后,它将 this
的每个索引从 length
开始设置,并将参数传递给 push()
。最后,它将 length
设置成之前的长度加上已添加元素的数量
const arrayLike = {
length: 3,
unrelated: "foo",
2: 4,
};
Array.prototype.push.call(arrayLike, 1, 2);
console.log(arrayLike);
// { '2': 4, '3': 1, '4': 2, length: 5, unrelated: 'foo' }
const plainObj = {};
// 这里没有长度属性,所以长度为 0
Array.prototype.push.call(plainObj, 1, 2);
console.log(plainObj);
// { '0': 1, '1': 2, length: 2 }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
4. 以类似数组的方式使用对象
如上所述,push
被有意设计为通用的,我们可以利用这一点。就像这个例子所展示的,Array.prototype.push
可以很好的处理对象。
注意,我们没有创建一个数组来存储对象集合。相反,我们将集合存储在对象本身上,并通过 Array.prototype.push
的 call
来调用该方法,让它认为我们正在处理一个数组——归功于 JavaScript 允许我们以任何我们想要的方式建立执行上下文的方式,这样是可行的。
const obj = {
length: 0,
addElem(elem) {
// obj.length 在每次添加元素时自动增加
[].push.call(this, elem);
},
};
// 让我们添加一些空对象来说明
obj.addElem({});
obj.addElem({});
console.log(obj.length); // 2
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
3.20 Array.prototype.reduce()🏳️🌈
数组中的每个元素从左到右进行缩减然后最后得到一个值
3.20.1 语法
reduce()
方法对数组中的每个元素按序执行一个提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。
第一次执行回调函数时,不存在“上一次的计算结果”。如果需要回调函数从数组索引为 0 的元素开始执行,则需要传递初始值。否则,数组索引为 0 的元素将被用作初始值,迭代器将从第二个元素开始执行(即从索引为 1 而不是 0 的位置开始)。
reduce(callbackFn)
reduce(callbackFn, initialValue)
- 1
- 2
callbackFn
为数组中每个元素执行的函数。其返回值将作为下一次调用 callbackFn
时的 accumulator
参数。对于最后一次调用,返回值将作为 reduce()
的返回值。该函数被调用时将传入以下参数:
-
accumulator
上一次调用
callbackFn
的结果。在第一次调用时,如果指定了initialValue
则为指定的值,否则为array[0]
的值。 -
currentValue
当前元素的值。在第一次调用时,如果指定了
initialValue
,则为array[0]
的值,否则为array[1]
。 -
currentIndex
currentValue
在数组中的索引位置。在第一次调用时,如果指定了initialValue
则为0
,否则为1
。 -
array
调用了
reduce()
的数组本身。
initialValue
第一次调用回调时初始化 accumulator
的值。如果指定了 initialValue
,则 callbackFn
从数组中的第一个值作为 currentValue
开始执行。如果没有指定 initialValue
,则 accumulator
初始化为数组中的第一个值,并且 callbackFn
从数组中的第二个值作为 currentValue
开始执行。在这种情况下,如果数组为空(没有第一个值可以作为 accumulator
返回),则会抛出错误。
返回值
使用“reducer”回调函数遍历整个数组后的结果
边界情况
如果数组只有一个元素(无论位置如何)且未提供 initialValue
,或者提供了 initialValue
但数组为空,则将返回该单个值,而不调用 callbackFn
。
如果提供了 initialValue
且数组不为空,则 reduce
方法将始终从索引 0 开始调用回调函数。
如果未提供 initialValue
,则对于长度大于 1、等于 1 和 0 的数组,reduce
方法将有不同的表现,如以下示例所示:
const getMax = (a, b) => Math.max(a, b);
// 从索引 0 开始为数组中的每个元素调用回调函数
[1, 100].reduce(getMax, 50); // 100
[50].reduce(getMax, 10); // 50
// 仅为索引 1 处的元素调用回调函数
[1, 100].reduce(getMax); // 100
// 不调用回调函数
[50].reduce(getMax); // 50
[].reduce(getMax, 1); // 1
[].reduce(getMax); // TypeError
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
3.20.2 示例
1. 无初始值时 reduce() 如何运行
const array = [15, 16, 17, 18, 19];
function reducer(accumulator, currentValue, index) {
const returns = accumulator + currentValue;
console.log(
`accumulator: ${accumulator}, currentValue: ${currentValue}, index: ${index}, returns: ${returns}`,
);
return returns;
}
array.reduce(reducer);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
回调函数会被调用四次,每次调用的参数和返回值如下表:
accumulator | currentValue | index | 返回值 | |
---|---|---|---|---|
第一次调用 | 15 | 16 | 1 | 31 |
第二次调用 | 31 | 17 | 2 | 48 |
第三次调用 | 48 | 18 | 3 | 66 |
第四次调用 | 66 | 19 | 4 | 85 |
array
参数在整个过程中始终不会改变——它始终是 [15, 16, 17, 18, 19]
。reduce()
返回的值将是最后一次回调返回值(85
)。
2. 有初始值时 reduce() 如何运行
在这里,我们以相同的算法 reduce 同一个数组,但提供 10
作为 initialValue
:
[15, 16, 17, 18, 19].reduce(
(accumulator, currentValue) => accumulator + currentValue,
10,
);
- 1
- 2
- 3
- 4
回调函数会被调用五次,每次调用的参数和返回值如下表:
accumulator | currentValue | index | 返回值 | |
---|---|---|---|---|
第一次调用 | 10 | 15 | 0 | 25 |
第二次调用 | 25 | 16 | 1 | 41 |
第三次调用 | 41 | 17 | 2 | 58 |
第四次调用 | 58 | 18 | 3 | 76 |
第五次调用 | 76 | 19 | 4 | 95 |
这种情况下 reduce()
返回的值是 95
。
3. 求对象数组中值的总和
为了对包含在对象数组中的值进行求和,必须提供一个 initialValue
,以便每个项都通过回调函数处理。
const objects = [{ x: 1 }, { x: 2 }, { x: 3 }];
const sum = objects.reduce(
(accumulator, currentValue) => accumulator + currentValue.x,
0,
);
console.log(sum); // 6
- 1
- 2
- 3
- 4
- 5
- 6
- 7
4. 展平嵌套数组
const flattened = [
[0, 1],
[2, 3],
[4, 5],
].reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);
// flattened 的值是 [0, 1, 2, 3, 4, 5]
- 1
- 2
- 3
- 4
- 5
- 6
5. 统计对象中值的出现次数
const people = [
{ name: "Alice", age: 21 },
{ name: "Max", age: 20 },
{ name: "Jane", age: 20 },
];
function groupBy(objectArray, property) {
return objectArray.reduce((acc, obj) => {
const key = obj[property];
const curGroup = acc[key] ?? [];
return { ...acc, [key]: [...curGroup, obj] };
}, {});
}
const groupedPeople = groupBy(people, "age");
console.log(groupedPeople);
// {
// 20: [
// { name: 'Max', age: 20 },
// { name: 'Jane', age: 20 }
// ],
// 21: [{ name: 'Alice', age: 21 }]
// }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
6. 按属性对对象进行分组
const people = [
{ name: "Alice", age: 21 },
{ name: "Max", age: 20 },
{ name: "Jane", age: 20 },
];
function groupBy(objectArray, property) {
return objectArray.reduce((acc, obj) => {
const key = obj[property];
const curGroup = acc[key] ?? [];
return { ...acc, [key]: [...curGroup, obj] };
}, {});
}
const groupedPeople = groupBy(people, "age");
console.log(groupedPeople);
// {
// 20: [
// { name: 'Max', age: 20 },
// { name: 'Jane', age: 20 }
// ],
// 21: [{ name: 'Alice', age: 21 }]
// }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
7. 数组去重
const myArray = ["a", "b", "a", "b", "c", "e", "e", "c", "d", "d", "d", "d"];
const myArrayWithNoDuplicates = myArray.reduce((accumulator, currentValue) => {
if (!accumulator.includes(currentValue)) {
return [...accumulator, currentValue];
}
return accumulator;
}, []);
console.log(myArrayWithNoDuplicates);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
8. 使用 reduce() 来替代 .filter().map()
使用 filter()
和 map()
会遍历数组两次,但是你可以使用 reduce()
只遍历一次并实现相同的效果,从而更高效。(如果你喜欢使用 for
循环,你可以在遍历一次时使用 forEach()
进行过滤和映射。)
const numbers = [-5, 6, 2, 0];
const doubledPositiveNumbers = numbers.reduce((accumulator, currentValue) => {
if (currentValue > 0) {
const doubled = currentValue * 2;
return [...accumulator, doubled];
}
return accumulator;
}, []);
console.log(doubledPositiveNumbers); // [12, 4]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
9. 使用组合函数实现管道
管道(pipe) 是一种将多个函数组合在一起的技术,使得一个函数的输出可以作为下一个函数的输入。这种方式可以提高代码的可读性和可维护性,尤其是在处理数据转换和处理时。
// 组合使用的构建块
const double = (x) => 2 * x;
const triple = (x) => 3 * x;
const quadruple = (x) => 4 * x;
// 函数组合,实现管道功能
const pipe =
(...functions) =>
(initialValue) =>
functions.reduce((acc, fn) => fn(acc), initialValue);
// 组合的函数,实现特定值的乘法
const multiply6 = pipe(double, triple);
const multiply9 = pipe(triple, triple);
const multiply16 = pipe(quadruple, quadruple);
const multiply24 = pipe(double, triple, quadruple);
// 用例
multiply6(6); // 36
multiply9(9); // 81
multiply16(16); // 256
multiply24(10); // 240
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
10.在稀疏数组上使用reduce()
console.log([1, 2, , 4].reduce((a, b) => a + b)); // 7
console.log([1, 2, undefined, 4].reduce((a, b) => a + b)); // NaN
- 1
- 2
11.在非数组对象中使用reduce()
reduce()
方法读取 this
的 length
属性,然后访问每个整数索引。
const arrayLike = {
length: 3,
0: 2,
1: 3,
2: 4,
};
console.log(Array.prototype.reduce.call(arrayLike, (x, y) => x + y));
// 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.21 Array.prototype.reduceRight()🏳️
和reduce如出一辙 只不过从右往左计算
3.21.1 语法
reduceRight()
方法对累加器(accumulator)和数组的每个值(按从右到左的顺序)应用一个函数,并使其成为单个值。
reduceRight(callbackFn)
reduceRight(callbackFn, initialValue)
- 1
- 2
callbackFn
为数组中的每个元素执行的函数。其返回值将作为下一次调用 callbackFn
时的 accumulator
参数。对于最后一次调用,返回值将成为 reduceRight()
的返回值。该函数被调用时将传入以下参数:
-
accumulator
上一次调用
callbackFn
的结果。在第一次调用时,如果指定了initialValue
则为指定的值,否则为数组最后一个元素的值。 -
currentValue
数组中当前正在处理的元素。
-
index
正在处理的元素在数组中的索引。
-
array
调用了
reduceRight()
的数组本身。initialValue
首次调用
callbackFn
时累加器的值。如果不提供初始值,则将使用数组中的最后一个元素,并在迭代时跳过它。没有初始值的情况下,在空数组上调用reduceRight()
会产生TypeError
。
返回值
聚合后的结果值。
3.21.2 示例
和reduce的用法一样 这里不多做赘述了
1. 示例
const array1 = [
[0, 1],
[2, 3],
[4, 5],
];
const result = array1.reduceRight((accumulator, currentValue) =>
accumulator.concat(currentValue),
);
console.log(result);
// Expected output: Array [4, 5, 2, 3, 0, 1]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
3.22 Array.prototype.reverse() 和toReverse()🏳️
reverse 反转
3.22.1 语法
reverse()
方法反转数组中的元素,并返回同一数组的引用。数组的第一个元素会变成最后一个,数组的最后一个元素变成第一个。换句话说,数组中的元素顺序将被翻转,变为与之前相反的方向。
toReversed()
方法是 reverse()
方法对应的复制版本。它返回一个元素顺序相反的新数组。
reverse()
toReversed()
- 1
- 2
返回值
原始数组反转后的引用。注意,数组是就地反转的,并且没有复制。
3.22.2 示例
1. reverse() 方法返回对同一数组的引用
reverse()
方法返回对原始数组的引用,因此改变返回的数组也会改变原始数组。
const numbers = [3, 2, 4, 1, 5];
const reversed = numbers.reverse();
// numbers 和 reversed 的顺序都是颠倒的 [5, 1, 4, 2, 3]
reversed[0] = 5;
console.log(numbers[0]); // 5
- 1
- 2
- 3
- 4
- 5
2. 对稀疏数组使用 reverse()
console.log([1, , 3].reverse()); // [3, empty, 1]
console.log([1, , 3, 4].reverse()); // [4, 3, empty, 1]
- 1
- 2
3. 非数组对象上使用reverse()
const arrayLike = {
length: 3,
unrelated: "foo",
2: 4,
};
console.log(Array.prototype.reverse.call(arrayLike));
// { '0': 4, length: 3, unrelated: 'foo' }
// 索引“2”被删除了,因为原本的数据中索引“0”不存在了
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.23 Array.prototype.shift()🏳️
shift 移动 移走第一个元素
3.23.1 语法
shift()
方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。
shift()
- 1
返回值
从数组中删除的元素;如果数组为空则返回 undefined
。
3.23.2 示例
1. 移除数组中的一个元素
const myFish = ["angel", "clown", "mandarin", "surgeon"];
console.log("调用 shift 之前:", myFish);
// 调用 shift 之前: ['angel', 'clown', 'mandarin', 'surgeon']
const shifted = myFish.shift();
console.log("调用 shift 之后:", myFish);
// 调用 shift 之后: ['clown', 'mandarin', 'surgeon']
console.log("被删除的元素:" + shifted);
// "被删除的元素:angel"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2. 在非数组对象上调用 shift()
shift
方法会读取 this
的 length
属性。如果规范化长度为 0,length
再次设置为 0
(而之前可能为负值或 undefined
)。否则,返回 0
处的属性,其余属性向左移动 1。length
属性递减 1。
const arrayLike = {
length: 3,
unrelated: "foo",
2: 4,
};
console.log(Array.prototype.shift.call(arrayLike));
// undefined,因为它是一个空槽
console.log(arrayLike);
// { '1': 4, length: 2, unrelated: 'foo' }
const plainObj = {};
// 这里没有长度属性,所以长度为 0
Array.prototype.shift.call(plainObj);
console.log(plainObj);
// { length: 0 }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
3.24 Array.prototype.slice()🏳️🌈
slice 切片
3.24.1 语法
slice()
方法返回一个新的数组对象,这一对象是一个由 start
和 end
决定的原数组的浅拷贝(包括 start
,不包括 end
),其中 start
和 end
代表了数组元素的索引。原始数组不会被改变
slice()
slice(start)
slice(start, end)
- 1
- 2
- 3
start
提取起始处的索引(从 0
开始),会转换为整数。默认为0
- 如果索引是负数,则从数组末尾开始计算——如果
start < 0
,则使用start + array.length
。 - 如果
start < -array.length
或者省略了start
,则使用0
。 - 如果
start >= array.length
,则不提取任何元素。
end
提取终止处的索引(从 0
开始),会转换为整数。slice()
会提取到但不包括 end
的位置。 默认为arr.length
- 如果索引是负数,则从数组末尾开始计算——如果
end < 0
,则使用end + array.length
。 - 如果
end < -array.length
,则使用0
。 - 如果
end >= array.length
或者省略了end
,则使用array.length
,提取所有元素直到末尾。 - 如果
end
在规范化后小于或等于start
,则不提取任何元素。
返回值
一个含有被提取元素的新数组。
3.24.2 示例
1. 返回现有数组的一部分
const fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
const citrus = fruits.slice(1, 3);
// fruits 包含 ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']
// citrus 包含 ['Orange','Lemon']
- 1
- 2
- 3
- 4
- 5
2. 在类数组对象上调用 slice()
slice()
方法会读取 this
对象的 length
属性,然后从 start
到 end
读取整数键属性,并将它们定义在一个新创建的数组中。
const arrayLike = {
length: 3,
0: 2,
1: 3,
2: 4,
};
console.log(Array.prototype.slice.call(arrayLike, 1, 3));
// [ 3, 4 ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3. 在稀疏数组上使用 slice()
如果源数组是稀疏数组,slice()
方法返回的数组也会是稀疏数组。
console.log([1, 2, , 4, 5].slice(1, 4)); // [2, empty, 4]
- 1
3.25 Array.prototype.sort()🏳️🌈
sort 排序
3.25.1 语法
sort()
方法就地对数组的元素进行排序,并返回对相同数组的引用。默认排序是将元素转换为字符串,然后按照它们的 UTF-16 码元值升序排序。他还有一个孪生兄弟,toSorted() 它可以创建一个排序后的副本,当然这个副本是浅拷贝的
sort()
sort(compareFn)
toSorted()
toSorted(compareFn)
- 1
- 2
- 3
- 4
compareFn
定义排序顺序的函数。返回值应该是一个数字,其符号表示两个元素的相对顺序:如果 a
小于 b
,返回值为负数,如果 a
大于 b
,返回值为正数,如果两个元素相等,返回值为 0
。NaN
被视为 0
。该函数使用以下参数调用:
-
a
第一个用于比较的元素。不会是
undefined
。 -
b
第二个用于比较的元素。不会是
undefined
。
如果省略该函数,数组元素会被转换为字符串,然后根据每个字符的 Unicode 码位值进行排序。
compareFn(a, b) 返回值 | 排序顺序 |
---|---|
> 0 | a 在 b 后,如 [b, a] |
< 0 | a 在 b 前,如 [a, b] |
=== 0 | 保持 a 和 b 原来的顺序 |
返回值
经过排序的原始数组的引用。注意数组是就地排序的,不会进行复制。
3.25.2 示例
1. 对象数组排序
const items = [
{ name: "Edward", value: 21 },
{ name: "Sharpe", value: 37 },
{ name: "And", value: 45 },
{ name: "The", value: -12 },
{ name: "Magnetic", value: 13 },
{ name: "Zeros", value: 37 },
];
// 根据 value 排序
items.sort((a, b) => a.value - b.value);
// 根据 name 排序
items.sort((a, b) => {
const nameA = a.name.toUpperCase(); // 忽略大小写
const nameB = b.name.toUpperCase(); // 忽略大小写
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
// name 必须相等
return 0;
});
- 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
2. 对象数组自定义排序
// 定义对象数组
const items = [
{ name: "apple", value: 1 },
{ name: "banana", value: 2 },
{ name: "cherry", value: 3 },
{ name: "date", value: 4 }
];
// 定义排序顺序
const order = ["banana", "apple", "cherry", "date"];
// 自定义排序函数
items.sort((a, b) => {
return order.indexOf(a.name) - order.indexOf(b.name);
});
// 输出排序后的结果
console.log(items);
// [
// { name: 'banana', value: 2 },
// { name: 'apple', value: 1 },
// { name: 'cherry', value: 3 },
// { name: 'date', value: 4 }
// ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
3. 在稀疏数组上使用 sort()
空槽会被移动到数组的末尾。
console.log(["a", "c", , "b"].sort()); // ['a', 'b', 'c', empty]
console.log([, undefined, "a", "b"].sort()); // ["a", "b", undefined, empty]
- 1
- 2
4. 在类数组对象上调用 sort()
sort()
方法会读取 this
的 length
属性。然后它会收集在 0
到 length - 1
范围内所有已存在的整数键属性,对它们进行排序,然后写回。如果范围内(即从 0 到 length - 1)存在缺失的属性,这些缺失的属性会被视为“不存在”,并在排序时被处理为排在末尾(就像稀疏数组一样)。
const arrayLike = {
length: 3,
unrelated: "foo",
0: 5,//1不存在
2: 4,
};
console.log(Array.prototype.sort.call(arrayLike));
// { '0': 4, '1': 5, length: 3, unrelated: 'foo' }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.26 Array.prototype.splice()🏳️🌈
拼接 可删可加的神奇方法
3.26.1 语法
splice()
方法就地移除或者替换已存在的元素,并可以添加新的元素。
splice(start)
splice(start, deleteCount)
splice(start, deleteCount, item1)
splice(start, deleteCount, item1, item2)
splice(start, deleteCount, item1, item2, /* …, */ itemN)
- 1
- 2
- 3
- 4
- 5
start
从 0 开始计算的索引,表示要开始改变数组的位置,它会被转换成整数。
- 负索引从数组末尾开始计算——如果
-buffer.length <= start < 0
,使用start + array.length
。 - 如果
start < -array.length
,使用0
。 - 如果
start >= array.length
,则不会删除任何元素,但是该方法会表现为添加元素的函数,添加所提供的那些元素。 - 如果
start
被省略了(即调用splice()
时不传递参数),则不会删除任何元素。这与传递undefined
不同,后者会被转换为0
。
deleteCount
可选
一个整数,表示数组中要从 start
开始删除的元素数量。
如果省略了 deleteCount
,或者其值大于或等于由 start
指定的位置到数组末尾的元素数量,那么从 start
到数组末尾的所有元素将被删除。但是,如果你想要传递任何 itemN
参数,则应向 deleteCount
传递 Infinity
值,以删除 start
之后的所有元素,因为显式的 undefined
会转换为 0
。
如果 deleteCount
是 0
或者负数,则不会移除任何元素。在这种情况下,你应该至少指定一个新元素(请参见下文)。
item1
、…、itemN
可选
从 start
开始要加入到数组中的元素。
如果不指定任何元素,splice()
将只从数组中删除元素。
返回值
一个包含了删除的元素的数组。
如果只移除一个元素,则返回一个元素的数组。
如果没有删除任何元素,则返回一个空数组。
3.26.2 示例
1. 示例
const months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// Inserts at index 1
console.log(months);
// Expected output: Array ["Jan", "Feb", "March", "April", "June"]
months.splice(4, 1, 'May');
// Replaces 1 element at index 4
console.log(months);
// Expected output: Array ["Jan", "Feb", "March", "April", "May"]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
2. 在稀疏数组中使用 splice()
splice()
方法保留了数组的稀疏性。
const arr = [1, , 3, 4, , 6];
console.log(arr.splice(1, 2)); // [empty, 3]
console.log(arr); // [1, 4, empty, 6]
- 1
- 2
- 3
- 4
3. 在非数组对象中使用 splice()
splice()
方法读取 this
的 length
属性。然后,它根据需要更新整数键属性和 length
属性。
const arrayLike = {
length: 3,
unrelated: "foo",
0: 5,
2: 4,
};
console.log(Array.prototype.splice.call(arrayLike, 0, 1, 2, 3));
// [ 5 ]
console.log(arrayLike);
// { '0': 2, '1': 3, '3': 4, length: 4, unrelated: 'foo' }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.27 Array.prototype[Symbol.iterator]()🏳️
3.27.1 语法
Array
实例的 [Symbol.iterator]()
方法实现了可迭代协议,允许数组被大多数期望可迭代对象的语法所使用,例如展开语法和 for...of
循环。它返回一个数组迭代器对象,该对象会产生数组中每个索引的值。
array[Symbol.iterator]()
- 1
返回值
与 Array.prototype.values()
相同的返回值:一个新的可迭代迭代器对象,它会生成数组中每个索引的值。
3.27.2 示例
1. 基础示例
const array1 = ['a', 'b', 'c'];
const iterator1 = array1[Symbol.iterator]();
for (const value of iterator1) {
console.log(value);
}
// Expected output: "a"
// Expected output: "b"
// Expected output: "c"
const arr = ["a", "b", "c", "d", "e"];
const arrIter = arr[Symbol.iterator]();
console.log(arrIter.next().value); // a
console.log(arrIter.next().value); // b
console.log(arrIter.next().value); // c
console.log(arrIter.next().value); // d
console.log(arrIter.next().value); // e
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
2. 使用相同的函数处理字符串和字符串数组
因为字符串和数组都实现了可迭代协议,所以可以设计一个通用函数以相同的方式处理这两种输入。这比直接调用 Array.prototype.values()
更好,后者要求输入是一个数组,或者至少是一个具有这种方法的对象。
function logIterable(it) {
if (typeof it[Symbol.iterator] !== "function") {
console.log(it, "不可迭代。");
return;
}
for (const letter of it) {
console.log(letter);
}
}
// 数组
logIterable(["a", "b", "c"]);
// a
// b
// c
// 字符串
logIterable("abc");
// a
// b
// c
// 数值
logIterable(123);
// 123 不可迭代。
- 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
3.28 Array.prototype.toLocaleString()🏳️
Array.prototype.toLocaleString() 是一个用于将数组转换为字符串的方法,且该字符串会根据用户的区域设置进行格式化
3.28.1 语法
toLocaleString()
方法返回一个字符串,表示数组中的所有元素。每个元素通过调用它们自己的 toLocaleString
方法转换为字符串,并且使用特定于语言环境的字符串(例如逗号“,”)分隔开。
toLocaleString()
toLocaleString(locales)
toLocaleString(locales, options)
- 1
- 2
- 3
locales
带有 BCP 47 语言标签的字符串,或者此类字符串的数组。对于 locales
参数的一般形式和说明,可以参见 Intl
主页面的参数说明。
options
一个具有配置属性的对象。对于数字,请参见 Number.prototype.toLocaleString()
;对于日期,请参见 Date.prototype.toLocaleString()
。
返回值
一个字符串,表示数组中的所有元素。
3.28.2 示例
1. 使用 locales 和 options
始终显示 prices
数组中字符串和数字的货币符号:
const prices = ["¥7", 500, 8123, 12];
prices.toLocaleString("ja-JP", { style: "currency", currency: "JPY" });
// "¥7,¥500,¥8,123,¥12"
- 1
- 2
- 3
- 4
- 5
2. 在稀疏数组中使用 toLocaleString()
toLocaleString()
将空槽视为 undefined
,并生成一个额外的分隔符:
console.log([1, , 3].toLocaleString()); // '1,,3'
- 1
3. 在非数组对象中使用 toLocaleString()
toLocaleString()
方法读取 this
的 length
属性,然后访问每个整数索引。
const arrayLike = {
length: 3,
0: 1,
1: 2,
2: 3,
};
console.log(Array.prototype.toLocaleString.call(arrayLike));
// 1,2,3
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3.29 Array.prototype.toString()🏳️
转化为string
3.29.1 语法
toString()
- 1
返回值
一个表示数组元素的字符串。
3.29.2 示例
1. 使用toString()
const array1 = [1, 2, "a", "1a"];
console.log(array1.toString()); // "1,2,a,1a"
- 1
- 2
- 3
- 4
2. 在稀疏数组中使用 toString()
与 join()
的行为一致,toString()
将空槽视为 undefined
并生成一个额外的分隔符:
console.log([1, , 3].toString()); // '1,,3'
- 1
3. 在非数组对象中使用 toString()
toString()
是通用的。它期望 this
具有 join()
方法;如果不存在,则使用 Object.prototype.toString()
。
console.log(Array.prototype.toString.call({ join: () => 1 }));
// 1; 一个数字
console.log(Array.prototype.toString.call({ join: () => undefined }));
// undefined
console.log(Array.prototype.toString.call({ join: "not function" }));
// "[object Object]"
- 1
- 2
- 3
- 4
- 5
- 6
3.30 Array.prototype.unshift()🏳️
unshift 取消移位 不把内容放在后面 而是放在前面 与push刚好反着
3.30.1 语法
unshift()
方法将指定元素添加到数组的开头,并返回数组的新长度。
unshift()
unshift(element1)
unshift(element1, element2)
unshift(element1, element2, /* …, */ elementN)
- 1
- 2
- 3
- 4
element1
、…、elementN
添加到 arr
开头的元素。
返回值
返回调用方法对象的新 length
属性。
3.30.2 示例
1. 使用 unshift()
const arr = [1, 2];
arr.unshift(0); // 调用的结果是 3,这是新的数组长度。
// 数组是 [0, 1, 2]
arr.unshift(-2, -1); // 新的数组长度是 5
// 数组是 [-2, -1, 0, 1, 2]
arr.unshift([-4, -3]); // 新的数组长度是 6
// 数组是 [[-4, -3], -2, -1, 0, 1, 2]
arr.unshift([-7, -6], [-5]); // 新的数组长度是 8
// 数组是 [ [-7, -6], [-5], [-4, -3], -2, -1, 0, 1, 2 ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
2. 在非数组对象中使用 unshift()
const arrayLike = {
length: 3,
unrelated: "foo",
2: 4,
};
Array.prototype.unshift.call(arrayLike, 1, 2);
console.log(arrayLike);
// { '0': 1, '1': 2, '4': 4, length: 5, unrelated: 'foo' }
const plainObj = {};
// 这里没有长度属性,所以这里的长的为 0
Array.prototype.unshift.call(plainObj, 1, 2);
console.log(plainObj);
// { '0': 1, '1': 2, length: 2 }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
3.31 Array.prototype.values()🏳️
values 数组的值
3.31.1 语法
values() 是专门为数组设计的,而 Symbol.iterator 是更通用的迭代器协议的一部分。实际上,Array.prototype.values() 实际上是调用 Array.prototype[Symbol.iterator]() 的一种方式,返回的迭代器在功能上是相同的。
values()
方法返回一个新的数组迭代器对象,该对象迭代数组中每个元素的值。跟Array.prototype[Symbol.iterator]() 是一样的
values()
- 1
返回值
一个新的可迭代迭代器对象。
3.31.2 示例
得到的返回值与Array.prototype[Symbol.iterator]()一样,这里不多做赘述
3.32 Array.prototype.with()🏳️
返回一个新的数组副本 并且附带(with)着一个修改的值
3.32.1 语法
Array
实例的 with()
方法是使用方括号表示法修改指定索引值的复制方法版本。它会返回一个新数组,其指定索引处的值会被新值替换。
arrayInstance.with(index, value)
- 1
index
要修改的数组索引(从 0 开始),将会转换为整数。
- 负数索引会从数组末尾开始计数——即当
index < 0
时,会使用index + array.length
。 - 如果规范化后的索引超出数组边界,会抛出
RangeError
。
value
要分配给指定索引的任何值
返回值
一个全新的数组,其中 index
索引处的元素被替换为 value
。
3.32.2 示例
1. 创建一个新的数组,改变其中一个元素
const arr = [1, 2, 3, 4, 5];
console.log(arr.with(2, 6)); // [1, 2, 6, 4, 5]
console.log(arr); // [1, 2, 3, 4, 5]
- 1
- 2
- 3
2. 在稀疏数组上使用 with()
with()
方法总会创建一个密集数组。空的部分用undefined填充
const arr = [1, , 3, 4, , 6];
console.log('原数组',arr)
console.log(arr.with(0, 2));
// 原数组 [ 1, <1 empty item>, 3, 4, <1 empty item>, 6 ]
// [ 2, undefined, 3, 4, undefined, 6 ]
- 1
- 2
- 3
- 4
- 5
- 6
3. 在非数组对象上调用 with()
with()
方法创建并返回一个新数组。它读取 this
的 length
属性,然后访问其键是小于 length
的非负整数的每个属性。当 this
的每个属性被访问后,索引等于该属性的键的数组元素被设置为该属性的值。最后,将 index
的数组值设置为 value
。
const arrayLike = {
length: 3,
unrelated: "foo",
0: 5,
2: 4,
3: 3, // 由于 length 属性的值为 3,with() 会忽略该值
};
console.log(Array.prototype.with.call(arrayLike, 0, 1));
// [ 1, undefined, 4 ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
如果以上教程有错误描述,欢迎来评论区批或者私信评指正