1. 前增 unshift() 改变原数组
在数组的开头添加一个或多个元素,并返回新的长度。
let arr = ["she", "he"];
let res = arr.unshift( "me" );
console.log( arr ); // ["me", "she", "he"]
console.log( res ); // 3 返回数组的长度
2. 后增 push() 改变原数组
在数组的末尾添加一个或多个元素,并返回新的长度。
let arr = ["she", "he"];
let res = arr.push( "me" );
console.log( arr ); // ["she", "he","me"]
console.log( res ); // 3 返回数组的长度
3. 前删 shift() 改变原数组
删除数组的第一个元素,返回删除的元素。
let arr = [ "she", "he" ];
let res = arr.shift();
console.log( arr ); // [ "he" ]
console.log( res ); // "she" 返回删除的元素
// (该方法不需要传递任何参数,因为它总是作用于数组的第一个元素。)
4. 后删 pop() 改变原数组
删除数组的最后一个元素,返回删除的元素。
let arr = [ "she", "he" ];
let res = arr.pop();
console.log( arr ); // [ "she" ]
console.log( res ); // "he" 返回删除的元素
// (该方法不需要传递任何参数,因为它总是作用于数组的最后一个元素。)
5. 改 splice ( start, deleteCount, item1, item2, ... ) 改变原数组
splice()
方法用于修改数组的内容,可以删除现有元素,或者添加新元素到数组中的指定位置。
start
: 指定修改的起始位置,即要修改的索引位置。deleteCount
: 可选参数,表示要删除的元素个数。如果为 0,则不删除元素,只添加新元素。item1, item2, ...
: 可选参数,要添加到数组中的新元素。splice()
方法返回被删除的元素组成的数组。如果没有删除任何元素,则返回一个空数组。
const arr = [1, 2, 3, 4, 5];
// 删除数组中的元素
const one = arr.splice(2, 2);
console.log(arr); // [1, 2, 5]
console.log(one); // [3, 4]
// 在指定位置插入新元素
const two = arr.splice(2, 0, 'a', 'b');
console.log(arr); // [1, 2, 'a', 'b', 5]
console.log(two); // []
// 替换元素
const three = arr.splice(3, 1, 'c', 'd');
console.log(arr); // [1, 2, 'a', 'c', 'd', 5]
console.log(three); // ['b']
/*
第一个 splice(2, 2) 删除了从索引 2 开始的两个元素(3 和 4),
返回被删除的元素组成的数组 [3, 4]。数组 arr 变为 [1, 2, 5]。
第二个 splice(2, 0, 'a', 'b') 在索引 2 的位置插入了两个新元素 'a' 和 'b',
返回一个空数组 []。数组 arr 变为 [1, 2, 'a', 'b', 5]。
第三个 splice(3, 1, 'c', 'd') 替换了索引 3 的元素,
返回被替换的元素组成的数组 ['b']。数组 arr 变为 [1, 2, 'a', 'c', 'd', 5]。
*/
6. 查 indexOf () 、 lastIndexOf () 、includes () 、find () 、findIndex() 不改变原数组
- indexOf (): 返回指定元素第一次出现的索引,如果未找到则返回 -1。(正查)
- lastIndexOf (): 返回指定元素最后一次出现的索引,如果未找到则返回 -1。(倒查)
- includes ( searchElement, fromIndex ): 判断数组是否包含某个元素,返回布尔值。
- find (callback( element, index, array ), thisArg): 用于查找数组中满足条件的第一个元素,并返回该元素的值。如果没有找到符合条件的元素,则返回
undefined
。find()
方法只会返回第一个满足条件的元素,后面的元素不会被检查。 -
// ------ find (callback( element, index, array ), thisArg) ---------- /* find() 方法的第一个参数是一个回调函数,用来测试数组中的每个元素。 该回调函数接收三个参数: element: 当前正在处理的元素。 index(可选):当前正在处理的元素的索引。 array(可选):调用 find() 方法的数组。 回调函数返回一个布尔值,以指示当前元素是否满足查找条件。如果返回 true, 则 find() 方法会返回当前元素的值;如果没有任何元素满足条件,则返回 undefined。 */
-
/* thisArg(可选): find() 方法的第二个参数 thisArg 是一个可选的参数, 用来指定在执行回调函数时,函数内部 this 的值。如果提供了 thisArg 参数, 则在调用回调函数时,会将 this 绑定到指定的值上。 如果省略了 thisArg 参数,则在调用回调函数时,this 的值将会是 undefined, 或者在严格模式下是全局对象(window 或 global)。 这两个参数使得 find() 方法非常灵活,可以根据具体的需求来进行条件查找, 并可以在回调函数中访问外部的对象或上下文。 */
- findIndex (callback( element, index, array ), thisArg): 用于查找数组中满足条件的第一个元素,并返回其索引值。如果没有找到符合条件的元素,则返回 -1。(参数和 find() 一样)
// ---------------- indexOf () 正查 -------------------------------
let arr = ["me", "she", "he"];
let res = arr.indexOf( "she" );
console.log( arr ); // ["me", "she", "he"]
console.log( res ); // 1 返回元素的下标 没找到则返回 -1
// ---------------- lastIndexOf() 倒查 ----------------------------
let arr = ["me", "she", "she", "he"];
let res = arr.lastIndexOf( "she" );
console.log( arr ); // ["me", "she", "she", "he"]
console.log( res ); // 2 返回元素的下标 没找到则返回 -1
// ---------------- includes(searchElement, fromIndex) -------------
/*
searchElement: 要查找的元素。
fromIndex(可选):开始查找的位置,默认为 0。
如果 fromIndex 为负数,则从数组的末尾向前查找。
*/
const numbers = [1, 2, 3, 4, 5];
const three = numbers.includes(3);
console.log(three); // true
const ten = numbers.includes(10);
console.log(ten); // false
// includes() 方法还可以指定起始搜索的位置
const numbers = [1, 2, 3, 4, 5];
const three = numbers.includes(3, 2);
console.log(three); // true
const two = numbers.includes(2, 3);
console.log(two); // false
/*
第一个 includes(3, 2),从索引 2 开始搜索元素 3,因此返回 true;
第二个 includes(2, 3),从索引 3 开始搜索元素 2,
但是 2 在索引 2 的位置,因此返回 false。
*/
关于 find() 方法的例子有点多,为不影响整体观看让其单独一个代码块
// ----------find (callback( element, index, array ), thisArg)--------------
/*
find() 方法的第一个参数 callback 是一个回调函数,它的可选参数是 index 和 array
*/
// ---------- 使用第一个参数 callback 的 可选参数 index 的例子
const numbers = [1, 2, 3, 4, 5];
const foundIndex = numbers.find((element, index) => {
return element > 2 && index > 1; // 查找大于 2 且索引大于 1 的元素
});
console.log(foundIndex); // 3
// ---------- 使用第一个参数 callback 的 可选参数 array 的例子
const numbers = [1, 2, 3, 4, 5];
const isLastEle = function(num, index, array) {
return index === array.length - 1; // 判断是否为数组的最后一个元素
};
const lastElement = numbers.find(isLastEle);
console.log(lastElement); // 5
/*
我们定义了一个回调函数 isLastEle,该函数用于判断当前元素是否为数组的最后一个元素。
通过访问 array.length 属性,我们可以在回调函数中获取到原始数组的长度,
并据此判断是否为最后一个元素。因为 5 是数组中的最后一个元素,所以返回 5。
*/
// ------------------使用第二个可选参数 thisArg 的例子-----------
/*
假设我们有一个包含学生信息的数组,并且我们想要查找特定分数范围内的学生。
我们可以使用 find() 方法来查找第一个符合条件的学生,
同时使用 thisArg 参数将特定的分数范围传递给回调函数。
*/
const students = [
{ name: '李白', score: 85 },
{ name: '杜甫', score: 92 },
{ name: '霍去病', score: 78 }
];
function range(student) {
return student.score >= this.minScore && student.score <= this.maxScore;
}
const criteria = {
minScore: 80,
maxScore: 90
};
const foundStudent = students.find(range, criteria);
console.log(foundStudent); // { name: '李白', score: 85 }
/*
我们定义了一个 range 函数,该函数用于判断学生的分数是否在指定的范围内。
然后,我们定义了一个 criteria 对象,该对象包含 minScore 和 maxScore 属性,
表示要搜索的分数范围。
最后,我们使用 find() 方法来查找第一个符合分数范围条件的学生对象,
并通过 thisArg 参数将 criteria 对象传递给回调函数,
以便在回调函数中访问到 minScore 和 maxScore 属性。
这样,我们就可以根据特定的条件来查找数组中的元素,
并且可以通过 thisArg 参数在回调函数中访问外部的对象或上下文。
*/
// ------ findIndex(callback( element, index, array ), thisArg) -------
const numbers = [5, 8, 12, 3, 17, 22];
const index = numbers.findIndex(element => element >= 10);
console.log(index); // 输出 2,因为 12 是第一个大于等于 10 的元素,它的索引是 2
7. 拼 concat () 不改变原数组
用于合并两个或多个数组,并返回一个新数组,不改变原数组。除了数组外,它还可以接受值作为参数,这些值将按顺序添加到新数组中。
// ------合并两个数组:-----------
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const newArray = array1.concat(array2);
console.log(newArray); // [1, 2, 3, 4, 5, 6]
// ------合并多个数组: -----------
const array1 = [1, 2];
const array2 = [3, 4];
const array3 = [5, 6];
const newArray = array1.concat(array2, array3);
console.log(newArray); // [1, 2, 3, 4, 5, 6]
// ------合并数组和值: -----------
const array1 = [1, 2, 3];
const newValue = 4;
const newArray = array1.concat(newValue);
console.log(newArray); // [1, 2, 3, 4]
// ------合并空数组: -------------
const array1 = [];
const array2 = [1, 2, 3];
const newArray = array1.concat(array2);
console.log(newArray); // [1, 2, 3]
// ------合并不同类型的值: --------
const array1 = [1, 2, 3];
const stringValue = "hello";
const objectValue = { name: "Alice" };
const newArray = array1.concat(stringValue, objectValue);
console.log(newArray); // [1, 2, 3, "hello", { name: "Alice" }]
8. 转 join (separator) 不改变原数组
- 用于将数组的所有元素连接成一个字符串。不改变原数组,返回一个新的字符串。
separator
:可选,指定连接各个元素的分隔符字符串。如果省略该参数,则默认使用逗号作为分隔符。
// 你可以指定一个字符串作为参数,该字符串将用作连接各个元素的分隔符。
// 如果不提供参数,默认使用逗号作为分隔符。
const array = ['apple', 'banana', 'orange'];
const result = array.join(); // 使用默认分隔符(逗号)连接数组元素
console.log(result); // "apple,banana,orange"
const array = ['apple', 'banana', 'orange'];
const result = array.join('-'); // 使用连字符作为分隔符连接数组元素
console.log(result); // "apple-banana-orange"
const array = [1, 2, 3, 4, 5];
const result = array.join(''); // 引号中间没有空格
console.log(result); // 输出 "12345"
- 补充:split ( separator, limit ) 方法 用于将一个字符串分割成子字符串数组,并返回一个新数组。
- 分割的位置由参数指定,该参数可以是字符串或正则表达式。原始字符串不会被修改。
// ---------- string.split(separator, limit) ----------
/*
separator:指定用于分割字符串的分隔符,可以是一个字符串或正则表达式。
如果省略该参数或参数为 undefined,则返回包含整个字符串的数组。
limit:可选,指定返回的数组的最大长度。如果省略该参数或参数为 0,
则返回包含所有子字符串的数组。
*/
const str = 'apple banana orange';
const result = str.split(' '); // 使用空格分割字符串
console.log(result); // ["apple", "banana", "orange"]
const str = 'apple,banana,orange';
const result = str.split(','); // 使用逗号分割字符串
console.log(result); // ["apple", "banana", "orange"]
const str = 'hello';
const result = str.split(''); 使用空字符串分割字符串(将字符串拆分为单个字符的数组)
console.log(result); // ["h", "e", "l", "l", "o"]
const str = 'apple,banana,orange';
const result = str.split(',', 2); // 限制返回数组的长度
console.log(result); // ["apple", "banana"]
// ---- 使用正则作为分隔符---------
const str = 'apple, banana;orange:grape';
// 使用正则表达式 /[,;:]/ 作为分隔符,表示逗号、分号和冒号都是分割符号
const result = str.split(/[,;:]/);
console.log(result); // ["apple", " banana", "orange", "grape"]
// 分割后的数组包含了逗号、空格、分号、冒号等字符
const str = 'Hello world, how are you?';
// 使用空格作为分隔符,/\s+/ 表示一个或多个空格
const result = str.split(/\s+/);
console.log(result); // ["Hello", "world,", "how", "are", "you?"]
// 字符串被空格分割成了单词
9. 排 sort ( compareFunction ) 改变原数组
- 用于对数组元素进行排序
- 它会原地排序数组,即改变原始数组,并返回排序后的数组。
- 其默认按照 Unicode 码点进行排序,但也可以传入一个比较函数来定义自定义的排序规则。
compareFunction
(可选):用于指定排序顺序的函数。如果省略,元素会按照转换为字符串的 Unicode 代码点进行排序。- sort ( (a, b)=> a-b ) 正序 sort ( (a, b)=> b-a ) 倒序
/*
compareFunction:是一个比较函数,用来定义排序规则。
它接受两个参数 a 和 b,分别表示要比较的两个元素。
如果返回值小于 0,则 a 排在 b 前面。
如果返回值等于 0,则 a 和 b 的相对位置不变。
如果返回值大于 0,则 b 排在 a 前面。
*/
const arr = ['banana', 'orange', 'apple', 'grape'];
arr.sort(); // 默认排序(按照 Unicode 码点)
console.log(arr) // ['apple', 'banana', 'grape', 'orange']
const arr = [40, 100, 1, 5, 25, 10];
arr.sort((a, b) => a - b); // 升序排列
console.log(arr) // [1, 5, 10, 25, 40, 100]
const arr = [40, 100, 1, 5, 25, 10];
arr.sort((a, b) => b - a); // 降序排列
console.log(arr) // [100, 40, 25, 10, 5, 1]
// 对象数组排序
const arr = [
{ name: 'John', age: 25 },
{ name: 'Jane', age: 30 },
{ name: 'Doe', age: 20 }
];
arr.sort((a, b) => a.age - b.age); // 按照年龄升序排列
console.log(arr)
// 结果:[
// { name: 'Doe', age: 20 },
// { name: 'John', age: 25 },
// { name: 'Jane', age: 30 }
// ]
const arr = ['a', 'B', 'c', 'D'];
arr.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
console.log(arr) // ['a', 'B', 'c', 'D'] (不区分大小写排序)
/*
在比较函数中,a 和 b 分别代表数组中的两个元素。
toLowerCase() 方法用于将字符串转换为小写形式,
localeCompare() 方法用于比较字符串,返回一个指示字符串之间关系的数字。
因此,通过 a.toLowerCase().localeCompare(b.toLowerCase()),
首先将 a 和 b 转换为小写形式,然后比较它们的字典顺序。
*/
10. 反转 reverse () 改变原数组
- 用于反转数组元素顺序,改变原数组,返回反转后的原数组。(
reverse()
方法返回反转后的数组,即原始数组的引用。) reverse()
方法不接受任何参数。
const arr = [1, 2, 3, 4, 5];
const reversedArr = arr.reverse();
console.log(reversedArr); // [5, 4, 3, 2, 1]
console.log(arr); // [5, 4, 3, 2, 1]
console.log(arr === reversedArr); // true
11. 截 slice ( start, end ) 不改变原数组
- 用于从数组中选取指定的元素,返回一个新的数组,原数组不会被修改。
- start(可选): 指定从哪个索引开始选取元素。如果省略该参数,则从数组的第一个元素开始选取。可以是负数,表示从数组末尾开始计数的位置。如果提供的值超出了数组的索引范围,或者是负数且绝对值大于数组的长度,则返回空数。
-
end(可选): 指定在哪个索引之前停止选取元素(但不包括该索引对应的元素)。如果省略该参数,则选取到数组的末尾。也可以是负数,表示从数组末尾开始计数的位置。如果提供的值超出了数组的索引范围,或者是负数且绝对值大于数组的长度,则会选取到数组的末尾。
-
总结:
slice()
方法选取的元素范围是从start
索引到end
索引之前(不包括end
对应的元素)。
// ------------选取指定范围的元素----------
const fruits = ['apple', 'banana', 'orange', 'grape', 'kiwi'];
const selectedFruits = fruits.slice(1, 3); // 从索引1到索引3(不包括索引3)选取元素
console.log(selectedFruits); // ['banana', 'orange']
console.log(fruits); // ['apple', 'banana', 'orange', 'grape', 'kiwi']
// --------不传入参数,复制整个数组--------
const originalArray = [1, 2, 3, 4, 5];
const copiedArray = originalArray.slice();
console.log(copiedArray); // [1, 2, 3, 4, 5]
// -------选取索引范围,负数索引表示从末尾开始计数-----
const numbers = [1, 2, 3, 4, 5];
// 从倒数第3个元素到倒数第1个元素(不包括倒数第1个)选取
const selectedNumbers = numbers.slice(-3, -1);
console.log(selectedNumbers); // [3, 4]
// -------超出数组范围的索引会被忽略-----------
const colors = ['red', 'green', 'blue'];
const selectedColors = colors.slice(1, 10); // 从索引1开始选取,超出范围的索引被忽略
console.log(selectedColors); // 输出: ['green', 'blue']
// ------可以用于将类数组对象转换为数组------
function func() {
const argsArray = Array.prototype.slice.call(arguments);
console.log(argsArray);
}
func(1, 2, 3); // [1, 2, 3]
12. 遍历 forEach ( callback ) 能改变原数组 无法return
- 用于在数组的每个元素上执行指定的函数,并且没有返回值(或者说总是返回 undefined)
forEach()
方法接受一个参数,即回调函数(callback function)。该回调函数可以接受三个参数,分别是当前元素的值、当前元素的索引和正在遍历的数组本身。- array.forEach( callback(currentValue, index, array) );
callback
: 用于对数组中的每个元素执行的函数。currentValue
: 当前数组元素的值(可选)。index
: 当前数组元素的索引(可选)。array
: 当前正在遍历的数组(可选)。
- 这些参数都是可选的,你可以只使用你需要的那些参数。通常,只需要使用第一个参数(当前元素的值),但在某些情况下,你可能需要使用索引或数组本身
const arr = [11, 22, 33];
const res = arr.forEach((v,i)=>{
arr[i] = v + 1;
return arr;
})
console.log(arr); // [12, 23, 34]
console.log(res); // undefined
const colors = ['red', 'green', 'blue'];
colors.forEach((color, index, array) => {
array[index] = color.toUpperCase();
});
console.log(colors); // ['RED', 'GREEN', 'BLUE']
13. 映射 map ( callback ) 不改变原数组 要return 返回新数组
- 用于遍历数组并对每个元素执行指定操作的方法。它会返回一个新的数组,该数组包含了对原始数组中每个元素执行操作后的结果,而不会修改原始数组。
- array.map( callback(currentValue, index, array), thisArg )
callback
: 用于对数组中的每个元素执行的函数。currentValue
: 当前元素的值。index
: 当前元素的索引(可选)。array
: 当前正在遍历的数组(可选)。
thisArg
(可选): 回调函数中的this
值。
// 对数组中的每个元素加倍
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map((number) => {
return number * 2;
});
console.log(doubledNumbers); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5]
// 使用索引参数
const numbers = [1, 2, 3, 4, 5];
const mappedNumbers = numbers.map((number, index) => {
return number + index;
});
console.log(mappedNumbers); // [1, 3, 5, 7, 9]
// 使用原始数组参数
const numbers = [1, 2, 3, 4, 5];
const mappedNumbers = numbers.map((number, index, array) => {
return number * array.length;
});
console.log(mappedNumbers); // [5, 10, 15, 20, 25]
// 使用thisArg参数
const numbers = [1, 2, 3, 4, 5];
const context = {
multiplier: 10
};
const mappedNumbers = numbers.map(function(number) {
return number * this.multiplier;
}, context);
console.log(mappedNumbers); // [10, 20, 30, 40, 50]
14. 过滤 filter ( callback ) 不改变原数组 要return 返回符合条件的新数组
- 用于从数组中过滤出满足指定条件的元素,并返回一个新的数组,不改变原数组。
filter()
方法返回一个新数组,包含通过测试的所有元素。- array.filter ( callback(currentValue, index, array), thisArg )
callback
: 用于测试每个元素的函数,返回 true 表示该元素通过测试,将被包含在新数组中。- currentValue: 当前元素的值。
index
: 当前元素的索引(可选)。array
: 当前正在遍历的数组(可选)。
thisArg
(可选): 回调函数中的this
值。
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evenNumbers = numbers.filter((number) => {
return number % 2 === 0;
});
console.log(evenNumbers); // [2, 4, 6, 8, 10]
console.log(numbers); [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 使用索引参数
const words = ['apple', 'banana', 'grape', 'orange', 'kiwi'];
const filteredWords = words.filter((word, index) => {
return index % 2 === 0;
});
console.log(filteredWords); // ['apple', 'grape', 'kiwi']
// 使用原始数组参数
const numbers = [10, 20, 30, 40, 50];
const filteredNumbers = numbers.filter((number, index, array) => {
return number > array[index - 1];
});
console.log(filteredNumbers); // [20, 30, 40, 50]
// 使用thisArg参数
const data = [10, 20, 30, 40, 50];
const context = {
threshold: 30
};
const filteredData = data.filter(function(number) {
return number > this.threshold;
}, context);
console.log(filteredData); // [40, 50]
15. 判断 some ( callback ) 、 every ( callback ) 不改变原数组 返回布尔值
- some ( callback ) : 用于检查数组中是否至少有一个元素满足指定条件。
- 如果有任意一个元素满足条件,则返回
true
;如果没有元素满足条件,则返回false。
- array.some ( callback(currentValue, index, array) );
callback
: 用于对数组中的每个元素执行的函数。currentValue
: 当前数组元素的值(可选)。index
: 当前数组元素的索引(可选)。array
: 当前正在遍历的数组(可选)。
- 这些参数都是可选的,你可以只使用你需要的那些参数。通常,只需要使用第一个参数(当前元素的值),但在某些情况下,你可能需要使用索引或数组本身
- every ( callback ) : 用于检查数组中的所有元素是否都满足指定条件。
- 如果所有元素都满足条件,则返回
true
;如果有任意一个元素不满足条件,则返回false。
- array.every ( callback(currentValue, index, array) ); ---(具体参数同some)
// some
const numbers = [1, 2, 3, 4, 5];
const hasEvenNumber = numbers.some((number) => {
return number % 2 === 0;
});
console.log(hasEvenNumber); // true
console.log(numbers) // [1, 2, 3, 4, 5]
// every
const numbers = [1, 2, 4, 6, 8, 10];
const allEvenNumbers = numbers.every((number) => {
return number % 2 === 0;
});
console.log(allEvenNumbers); // false
16. 迭代 reduce ( callback, initilValue ) 不改变原数组 返回一个累加的结果值
- 用于累加数组元素。
reduce()
方法主要用于对数组中的元素进行累加、累乘、字符串连接等操作。- array.reduce ( callback(accumulator, currentValue, index, array), initialValue )
callback
: 用于执行归约操作的函数。accumulator
: 累加器累计回调的返回值。它是累计计算的结果,也可以被称为累加值。currentValue
: 当前数组元素的值。index
: 当前元素的索引(可选)。array
: 当前正在遍历的数组(可选)。
initialValue
(可选): 作为第一次调用callback
函数时的第一个参数的值。
// 求和
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => {
return accumulator + currentValue;
}, 0);
console.log(sum); // 15
/*
accumulator 是累加器,它在每次迭代中累积计算的结果。
currentValue 是当前数组元素的值。
在每次迭代中,accumulator 的初始值为 0,currentValue 分别为数组中的每个元素。
具体的迭代过程如下:
第一次迭代:accumulator 的初始值为 0,currentValue 为数组中的第一个元素 1。
计算结果为 0 + 1 = 1。
第二次迭代:accumulator 的值为上一次迭代的结果 1,currentValue 为数组中的第二个元素 2。
计算结果为 1 + 2 = 3。
第三次迭代:accumulator 的值为上一次迭代的结果 3,currentValue 为数组中的第三个元素 3。
计算结果为 3 + 3 = 6。
第四次迭代:accumulator 的值为上一次迭代的结果 6,currentValue 为数组中的第四个元素 4。
计算结果为 6 + 4 = 10。
第五次迭代:accumulator 的值为上一次迭代的结果 10,currentValue 为数组中的第五个元素 5。
计算结果为 10 + 5 = 15。
最终,sum 的值为 15,即数组中所有元素的累加和。
*/
// 求积
const numbers = [1, 2, 3, 4, 5];
const product = numbers.reduce((accumulator, currentValue) => {
return accumulator * currentValue;
}, 1);
console.log(product); // 120
// 数组扁平化: 将多维数组转换为一维数组
const nestedArray = [[1, 2], [3, 4], [5, 6]];
const flattenedArray = nestedArray.reduce((accumulator, currentValue) => {
return accumulator.concat(currentValue);
}, []);
console.log(flattenedArray); // [1, 2, 3, 4, 5, 6]
// 使用 reduce() 方法对更深层次的数组进行扁平化
const deepNestedArray = [1, [2, [3, 4], 5], 6, [7, 8]];
const flattenDeepArray = function(arr) {
return arr.reduce((accumulator, currentValue) => {
if (Array.isArray(currentValue)) {
return accumulator.concat(flattenDeepArray(currentValue));
} else {
return accumulator.concat(currentValue);
}
}, []);
};
const flattenedArray = flattenDeepArray(deepNestedArray);
console.log(flattenedArray); // [1, 2, 3, 4, 5, 6, 7, 8]
/*
定义了一个名为 flattenDeepArray 的函数,它接受一个数组作为参数,
并使用 reduce() 方法对数组进行扁平化。
在 reduce() 的回调函数中,我们检查当前元素是否为数组。
如果是数组,则递归调用 flattenDeepArray 函数,直到将所有嵌套的数组扁平化为一维数组。
如果当前元素不是数组,则将其直接连接到累加器中。
最终,flattenedArray 将包含扁平化后的一维数组 [1, 2, 3, 4, 5, 6, 7, 8]。
*/
// 数组去重
function removeDuplicates(arr) {
// 使用 reduce 方法遍历数组,累积非重复的元素
return arr.reduce((accumulator, currentValue) => {
// 如果当前元素不在累加器中,则将其添加到累加器中
if (!accumulator.includes(currentValue)) {
accumulator.push(currentValue);
}
return accumulator;
}, []);
}
const arr = [1, 2, 3, 3, 4, 4, 5, 6, 6, 7];
let result = removeDuplicates(arr)
console.log(result); // [1, 2, 3, 4, 5, 6, 7]
console.log(arr); // [1, 2, 3, 3, 4, 4, 5, 6, 6, 7]
17. 变 Array.from ( arrayLike, mapFn,thisArg ) 不改变原数组 将伪数组转为真实数组 (记第一个参数就行,后面俩没必要)
- 用于从类似数组或可迭代对象创建一个新的数组实例。
- 它接受一个类数组对象或可迭代对象,并返回一个新的数组实例,其中包含对象的所有元素。
Array.from()
的一个常见用途是将类数组对象(例如函数的arguments
对象)转换为真正的数组,以便可以应用数组方法。- Array.from ( arrayLike, mapFn,thisArg )
-
arrayLike
:要转换为数组的类数组对象或可迭代对象。这是唯一必需的参数。 -
mapFn
(可选):对数组中的每个元素进行映射的函数,类似于Array.prototype.map()
方法。这个函数会在每个元素上被调用,并将元素的值作为第一个参数传入。mapFn
函数可以返回新的元素值,最终形成新的数组。如果不提供这个参数,则默认为将数组中的每个元素直接映射为相同的值。 -
thisArg
(可选):执行mapFn
时的this
值。如果提供了这个参数,在调用mapFn
函数时,this
将会指向thisArg
。如果省略了这个参数,则默认为undefined
。
// ------------------- arrayLike参数 ---------------
// 从字符串创建一个数组
const str = 'hello';
const strArray = Array.from(str);
console.log(strArray); // ["h", "e", "l", "l", "o"]
// 从Set对象创建一个数组
const set = new Set([1, 2, 3, 4, 5]);
const setArray = Array.from(set);
console.log(setArray); // [1, 2, 3, 4, 5]
/*
set 虽然看起来像是一个数组,但实际上是一个 Set 对象,而不是数组。
尽管在初始化时传入了一个数组 [1, 2, 3, 4, 5] 给 Set 构造函数,
但 Set 构造函数会将这个数组作为初始值,并根据数组中的元素来创建一个新的 Set 对象。
与数组不同,Set 是一种特殊的集合类型,它的元素是唯一的,且是无序的。
虽然 Set 与数组类似,但它们有着不同的特性和用法。
在上述代码中,set 是一个包含了唯一值 [1, 2, 3, 4, 5] 的 Set 对象,而不是一个数组。
*/
// ------------------- mapFn参数 ---------------
const numbers = [1, 2, 3, 4, 5];
// 使用 Array.from() 方法将数组中的每个元素进行平方操作并存储在新数组中
const squares = Array.from(numbers, num => num * num);
console.log(squares); // [1, 4, 9, 16, 25]
// !!!!!不建议这么用,都已经是数组了,直接用数组的方法就行。 thisArg参数同理。
17.1 Set 数据结构 --扩展
- Set 是 JavaScript 中的一种数据结构,用于存储唯一的值。
- Set 本身是一个构造函数,用来生成Set数据结构。
-
唯一性:Set 中的元素是唯一的,即相同的值在 Set 中只会出现一次。如果尝试向 Set 中添加一个已经存在的值,那么这个值不会被添加,Set 中仍然只会保留一个该值。
-
无序性:Set 中的元素是无序存储的,即没有按照特定顺序排序。因此,不能像数组那样通过索引来访问 Set 中的元素。Set 中的元素顺序是根据它们添加到 Set 中的顺序确定的,但不保证元素的顺序。
-
元素的任意性:在 Set 中可以存储任何类型的值,包括原始类型和对象引用等。
-
不重复值:Set 内部的元素不允许重复,这使得 Set 成为一种很好的数据结构来存储不重复的值,例如去除数组中的重复元素。
-
集合操作:Set 提供了一些方便的方法来执行集合操作,如并集、交集、差集等。这些方法包括
add()
、delete()
、has()
、clear()
等。 -
迭代:Set 是可迭代的,可以使用
for...of
循环、forEach()
方法等来遍历 Set 中的元素。 -
应用场景:Set 在许多场景下都很有用,例如去除数组中的重复元素、存储不重复的值、检查值是否存在等。
// 唯一性,不重复性 数组去重。
const s = new Set();
[1, 2, 2, 3, 4, 5, 5].forEach(x => s.add(x));
for(let i of s){
console.log(i)
}
// 1,2,3,4,5
// 通过Set的add方法向Set结构加入成员,表明Set结构不会添加重复的值。
const set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
// ---- 去除数组重复成员的方法 -----
//去除数组的重复成员
[...new Set(array)]
// 也可以用于,去除字符串里面的重复字符。
[...new Set('ababbc')].join('')
// "abc"
- 向 Set 加入值的时候,不会发生类型转换,所以
5
和"5"
是两个不同的值。Set 内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,它类似于精确相等运算符(===
),主要的区别是向 Set 加入值时认为NaN
等于自身,而精确相等运算符认为NaN
不等于自身。 - 另外,两个对象总是不相等的。
let set = new Set();
let a = NaN;
let b = NaN;
set.add(a);
set.add(b);
set // Set {NaN}
let set = new Set();
set.add({});
set.size // 1
set.add({});
set.size // 2
Set 结构的实例有以下属性。
Set.prototype.constructor
:构造函数,默认就是Set
函数。Set.prototype.size
:返回Set
实例的成员总数。
Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。
Set.prototype.add(value)
:添加某个值,返回 Set 结构本身。Set.prototype.delete(value)
:删除某个值,返回一个布尔值,表示删除是否成功。Set.prototype.has(value)
:返回一个布尔值,表示该值是否为Set
的成员。Set.prototype.clear()
:清除所有成员,没有返回值。
s.add(1).add(2).add(2);
// 注意2被加入了两次
s.size // 2
s.has(1) // true
s.has(2) // true
s.has(3) // false
s.delete(2);
s.has(2) // false
Set 结构的实例有四个遍历方法,可以用于遍历成员。
Set.prototype.keys()
:返回键名的遍历器Set.prototype.values()
:返回键值的遍历器Set.prototype.entries()
:返回键值对的遍历器Set.prototype.forEach()
:使用回调函数遍历每个成员
需要特别指出的是,Set
的遍历顺序就是插入顺序。这个特性有时非常有用,比如使用 Set 保存一个回调函数列表,调用时就能保证按照添加顺序调用。
.........详看阮一峰老师写的:https://www.bookstack.cn/read/es6-3rd/spilt.1.docs-set-map.md
Array.from()
方法可以将 Set 结构转为数组。
const items = new Set([1, 2, 3, 4, 5]);
const array = Array.from(items);
这就提供了去除数组重复成员的另一种方法。
function dedupe(array) {
return Array.from(new Set(array));
}
dedupe([1, 1, 2, 3]) // [1, 2, 3]
18. 创 Array.of() 创建一个新的数组实例
- 用于创建一个新的数组实例,它接受一系列参数并返回一个新的数组。
- 这个方法的主要目的,是弥补数组构造函数
Array()
的不足。因为参数个数的不同,会导致Array()
的行为有差异。
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
/*
Array方法没有参数、一个参数、三个参数时,返回结果都不一样。只有当参数个数不少于 2 个时,
Array()才会返回由参数组成的新数组。参数个数只有一个时,实际上是指定数组的长度。
*/
- 与
Array
构造函数不同,Array.of()
在接受一个参数时不会将其视为数组的长度,而是将其作为数组的第一个元素。 -
创建数组:
Array.of()
方法用于创建一个新的数组实例。与直接使用数组字面量[ ]
或new Array()
构造函数创建数组不同,Array.of()
可以直接接受一系列参数并返回一个包含这些参数的新数组。 -
处理参数:
Array.of()
方法会将传入的参数作为数组的元素。无论参数是什么类型,它们都会被作为新数组的元素,而不是数组的长度。 -
处理单个参数:与
Array
构造函数不同,Array.of()
在接受单个参数时不会将其视为数组的长度。它会将这个参数作为数组的第一个元素。
const arr1 = Array.of(1, 2, 3, 4, 5); // 创建一个包含数字的数组
console.log(arr1); // [1, 2, 3, 4, 5]
const arr2 = Array.of('a', 'b', 'c'); // 创建一个包含字符串的数组
console.log(arr2); // ["a", "b", "c"]
const arr3 = Array.of(5); // 创建一个包含一个元素的数组,元素值为 5
console.log(arr3); // [5]
19. 复覆 copyWithin( target, start, end ) 改变原数组 返回修改后的数组
- 用于在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员)。该方法不会改变数组的长度,会改变当前数组,返回修改后的数组。
- arr.copyWithin( target, start, end )
target
:必需,复制的目标位置,即开始替换数据的位置。如果为负值,表示倒数。start
:可选,从该位置开始复制数据,默认值为 0。如果为负值,表示从数组末尾开始计算。end
:可选,结束复制的位置(不包含),默认值为数组长度。如果为负值,表示从数组末尾开始计算。
const array1 = [1, 2, 3, 4, 5];
// 将数组中索引为 0 的元素复制到索引为 3 的位置开始
console.log(array1.copyWithin(3, 0)); // [1, 2, 3, 1, 2]
const array2 = ['a', 'b', 'c', 'd', 'e'];
// 将数组中从索引为 0 到 2(不包含)的元素复制到索引为 2 的位置开始
console.log(array2.copyWithin(2, 0, 2)); // ["a", "b", "a", "b", "e"]
// 将3号位复制到0号位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
// [4, 2, 3, 4, 5]
// -2相当于3号位,-1相当于4号位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(0, 1, 4);
// [2, 3, 4, 4, 5]
20. 填覆 fill (value, start, end) 改变原数组 返回修改后的数组
fill
方法使用给定值,填充一个数组。修改原始数组,并返回修改后的数组。- arr.fill ( value, start, end )
value
:必需,用来填充数组元素的值。start
:可选,起始索引,默认值为 0。如果为负值,表示从数组末尾开始计算。end
:可选,结束索引(不包含),默认值为数组的长度。如果为负值,表示从数组末尾开始计算。
const arr = [1, 2, 3, 4, 5];
// 将数组中所有元素替换为 0
console.log(arr.fill(0)); // [0, 0, 0, 0, 0]
// 将数组中从索引为 2 的位置开始到索引为 4 的位置(不包含)的元素替换为 9
console.log(arr.fill(9, 2, 4)); // [0, 0, 9, 9, 0]
// 创建一个长度为 5 的数组并用 0 填充
const arr = new Array(5).fill(0);
console.log(arr); // 输出: [0, 0, 0, 0, 0]
21. 遍历family entries()、keys() 、 values() 都不需要任何参数
ntries()
,keys()
和values()
——用于遍历数组。它们都返回一个迭代器对象,可以用for...of
循环进行遍历keys()
是对键名的遍历、values()
是对键值的遍历,entries()
是对键值对的遍历。- 当你在处理数组时,有时你需要迭代数组的元素或者获取它们的索引或值就可以用它们。
entries()
- 参数:
entries()
方法不接受任何参数。 - 返回值: 返回一个新的迭代器对象,该对象包含数组中每个索引位置的键值对。
const arr = ['a', 'b', 'c'];
// 使用 entries() 方法获取迭代器对象
const entriesIterator = arr.entries();
// 使用 for...of 循环遍历迭代器对象
for (let entry of entriesIterator) {
console.log(entry);
}
// 输出:
// [0, 'a'] // 索引为0,值为'a'
// [1, 'b'] // 索引为1,值为'b'
// [2, 'c'] // 索引为2,值为'c'
keys ()
- 参数:
keys()
方法不接受任何参数。 - 返回值: 返回一个新的迭代器对象,该对象包含数组中每个索引位置的键。
const arr = ['a', 'b', 'c'];
// 使用 keys() 方法获取迭代器对象
const keysIterator = arr.keys();
// 使用 for...of 循环遍历迭代器对象
for (let key of keysIterator) {
console.log(key);
}
// 输出:
// 0 // 索引为0
// 1 // 索引为1
// 2 // 索引为2
values ()
- 参数:
values()
方法不接受任何参数。 - 返回值: 返回一个新的迭代器对象,该对象包含数组中每个索引位置的值。
const arr = ['a', 'b', 'c'];
// 使用 values() 方法获取迭代器对象
const valuesIterator = arr.values();
// 使用 for...of 循环遍历迭代器对象
for (let value of valuesIterator) {
console.log(value);
}
// 输出:
// 'a' // 值为'a'
// 'b' // 值为'b'
// 'c' // 值为'c'
22. 扁平化 flat() 、flatMap() 不改变原数组 返回扁平化后的新数组
flat()
方法用于将多维数组扁平化为一维数组。不改变原数组,返回扁平化后的新数组。depth
(可选):指定要扁平化嵌套数组的层级深度,默认值为 1。如果需要完全扁平化数组,可以传入一个无穷大的正整数(如Infinity
)。- 如果原数组有空位,
flat()
方法会跳过空位。
const arr = [1, 2, [3, 4], [5, [6, 7]]];
const flatArray = arr.flat();
console.log(arr); // [1, 2, [3, 4], [5, [6, 7]]] 原始数组不变
console.log(flatArray); // [1, 2, 3, 4, 5, [6, 7]] 新数组
/*
flat()默认只会拉平一层,如果想要拉平多层的嵌套数组,
可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1。
*/
const arr = [1, 2, [3, 4], [5, [6, 7]]];
const flatArray = arr.flat(2);
console.log(arr); // [1, 2, [3, 4], [5, [6, 7]]] 原始数组不变
console.log(flatArray); // [1, 2, 3, 4, 5, 6, 7] 新数组
// 如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。
console.log([1, [2, [3,[4,5]]]].flat(Infinity)); // [1, 2, 3, 4, 5]
// 如果原数组有空位,flat()方法会跳过空位。
console.log([1, 2, , 4, 5].flat()); // [1, 2, 4, 5]
flatMap()
方法是 JS数组的一个高阶函数,它结合了map()
和flat()
两个方法的功能。它首先对数组中的每个元素执行一个指定的回调函数,然后将结果压缩成一个新数组,最后将新数组扁平化为一维数组。flatMap()
会自动移除返回数组中的空项,并且默认情况下仅扁平化一层数组。如果需要更深层次的扁平化,可以使用flatMap()
方法的回调函数返回一个多维数组。- 相较于先使用
map()
再使用flat()
,flatMap()
在处理单一映射和扁平化步骤时可能更高效,因为它只遍历数组一次。 - 如果你只需要扁平化,用
flat()
;如果你需要扁平化的同时转换元素,flatMap()
则更为便捷且高效。 - arr.flatMap ( callback( currentValue, index, array), thisArg )
callback
:要为每个元素调用的回调函数,该函数可以接受三个参数:currentValue
:当前正在处理的元素。index
(可选):当前正在处理的元素的索引。array
(可选):调用flatMap()
方法的数组。thisArg
(可选):执行回调函数时使用的this
值。
const arr = [1, 2, 3];
const result = arr.flatMap((num) => [num * 2, num * 3]);
console.log(result); // [2, 3, 4, 6, 6, 9]
const words = ['hello', 'cai'];
// 对每个单词进行分割,并将结果展开到一个新数组
const letters = words.flatMap(word => word.split(''));
console.log(letters); // ['h', 'e', 'l', 'l', 'o', 'c', 'a', 'i']
// -------flatMap() 方法将深层次的多维数组扁平化至一维数组 ----------
const arr = [1, 2, [3, [4, 5]], [6, [7, 8, [9, 10]]]];
const deeplyFlattenedArray = arr.flatMap(num => {
if (Array.isArray(num)) {
return num.flatMap(innerNum => {
if (Array.isArray(innerNum)) {
return innerNum; // 返回嵌套数组
} else {
return [innerNum]; // 返回单个元素组成的数组
}
});
} else {
return [num]; // 返回单个元素组成的数组
}
});
console.log(deeplyFlattenedArray); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
23. 是否是数组 Array.isArray(value)
- 参数:
value
:要检查的值。
- 返回值:
- 如果
value
是一个数组,则返回true,
否则false。
- 如果
Array.isArray([1, 2, 3]); // true
Array.isArray({}); // false
Array.isArray('hello'); // false
Array.isArray(123); // false
Array.isArray(null); // false
Array.isArray(undefined); // false
24. 支负 at (index) 返回指定索引位置的元素
- arr.at ( index )
- 参数:
index
:要获取元素的索引位置。可以是一个正整数或者负整数。如果索引为负数,表示从数组末尾开始计算索引,-1 表示倒数第一个元素。
- 返回值:
- 返回指定索引位置的元素。如果索引超出了数组的范围,则返回
undefined
。
- 返回指定索引位置的元素。如果索引超出了数组的范围,则返回
Array.prototype.at()
方法与普通的索引访问方式arr[index]
不同之处在于,它可以正确处理负索引,并且对于超出数组范围的索引,不会抛出异常而是返回undefined
。
- 长久以来,JavaScript 不支持数组的负索引,如果要引用数组的最后一个成员,不能写成
arr[-1]
,只能使用arr[arr.length - 1]
。- 这是因为方括号运算符
[]
在 JavaScript 语言里面,不仅用于数组,还用于对象。对于对象来说,方括号里面就是键名,比如obj[1]
引用的是键名为字符串1
的键,同理obj[-1]
引用的是键名为字符串-1
的键。由于 JavaScript 的数组是特殊的对象,所以方括号里面的负数无法再有其他语义了,也就是说,不可能添加新语法来支持负索引。- 为了解决这个问题,ES2022 为数组实例增加了
at()
方法,接受一个整数作为参数,返回对应位置的成员,并支持负索引。这个方法不仅可用于数组,也可用于字符串和类型数组(TypedArray)。
const array = ['a', 'b', 'c', 'd', 'e'];
console.log(array.at(2)); // 输出:'c'
console.log(array.at(-1)); // 输出:'e'
console.log(array.at(6)); // 输出:undefined
25. 保原 toReversed()、toSorted()、toSpliced()、with() 不改变原数组
很多数组的传统方法会改变原数组,比如
push()
、pop()
、shift()
、unshift()
等等。数组只要调用了这些方法,它的值就变了。现在有一个提案,允许对数组进行操作时,不改变原数组,而返回一个原数组的拷贝。
Array.prototype.toReversed() -> Array
Array.prototype.toSorted(compareFn) -> Array
Array.prototype.toSpliced(start, deleteCount, ...items) -> Array
Array.prototype.with(index, value) -> Array
它们分别对应数组的原有方法。
toReversed()
对应reverse()
,用来颠倒数组成员的位置。toSorted()
对应sort()
,用来对数组成员排序。toSpliced()
对应splice()
,用来在指定位置,删除指定数量的成员,并插入新成员。with(index, value)
对应splice(index, 1, value)
,用来将指定位置的成员替换为新的值。上面是这四个新方法对应的原有方法,含义和用法完全一样,唯一不同的是不会改变原数组,而是返回原数组操作后的拷贝。
const sequence = [1, 2, 3];
sequence.toReversed() // [3, 2, 1]
sequence // [1, 2, 3]
const outOfOrder = [3, 1, 2];
outOfOrder.toSorted() // [1, 2, 3]
outOfOrder // [3, 1, 2]
const array = [1, 2, 3, 4];
array.toSpliced(1, 2, 5, 6, 7) // [1, 5, 6, 7, 4]
array // [1, 2, 3, 4]
const correctionNeeded = [1, 1, 3];
correctionNeeded.with(1, 2) // [1, 2, 3]
correctionNeeded // [1, 1, 3]
26. 分组 group(),groupToMap()
- 数组成员分组是一个常见需求,数组实例方法
group()
和groupToMap()
,它们可以根据分组函数的运行结果,将数组成员分组。 group()
的参数是一个分组函数,原数组的每个成员都会依次执行这个函数,确定自己是哪一个组。
const array = [1, 2, 3, 4, 5];
array.group((num, index, array) => {
return num % 2 === 0 ? 'even': 'odd';
});
// { odd: [1, 3, 5], even: [2, 4] }
group()
的分组函数可以接受三个参数,依次是数组的当前成员、该成员的位置序号、原数组(上例是num
、index
和array
)。分组函数的返回值应该是字符串(或者可以自动转为字符串),以作为分组后的组名。
group()
的返回值是一个对象,该对象的键名就是每一组的组名,即分组函数返回的每一个字符串(上例是even
和odd
);该对象的键值是一个数组,包括所有产生当前键名的原数组成员。
[6.1, 4.2, 6.3].group(Math.floor)
// { '4': [4.2], '6': [6.1, 6.3] }
上面示例中,
Math.floor
作为分组函数,对原数组进行分组。它的返回值原本是数值,这时会自动转为字符串,作为分组的组名。原数组的成员根据分组函数的运行结果,进入对应的组。
group()
还可以接受一个对象,作为第二个参数。该对象会绑定分组函数(第一个参数)里面的this
,不过如果分组函数是一个箭头函数,该对象无效,因为箭头函数内部的this
是固化的。
groupToMap()
的作用和用法与group()
完全一致,唯一的区别是返回值是一个 Map 结构,而不是对象。Map 结构的键名可以是各种值,所以不管分组函数返回什么值,都会直接作为组名(Map 结构的键名),不会强制转为字符串。这对于分组函数返回值是对象的情况,尤其有用。
const array = [1, 2, 3, 4, 5];
const odd = { odd: true };
const even = { even: true };
array.groupToMap((num, index, array) => {
return num % 2 === 0 ? even: odd;
});
// Map { {odd: true}: [1, 3, 5], {even: true}: [2, 4] }
上面示例返回的是一个 Map 结构,它的键名就是分组函数返回的两个对象
odd
和even
。总之,按照字符串分组就使用
group()
,按照对象分组就使用groupToMap()
。