all
Array.prototype.concat()
Array.prototype.concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
语法
var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
- valueN可选: 数组和/或值,将被合并到一个新的数组中。如果省略了所有valueN参数,则concat会返回调用此方法的现存数组的一个浅拷贝。
- 如果
valueN
为字符串,数字和布尔(不是String,Number 和 Boolean 对象),concat将字符串和数字的值复制到新数组中。 - 如果
valueN
为对象引用,concat将对象引用复制到新数组中。 原始数组和新数组都引用相同的对象。 也就是说,如果引用的对象被修改,则更改对于新数组和原始 数组都是可见的。
- 如果
返回值
新的 Array 实例。
应用
-
合并多个值
const array = [1,2,3,4];
const arrayCopy = array.concat('哈哈','哇哇');
console.log(arrayCopy); // [1, 2, 3, 4, '哈哈', '哇哇'] -
合并多个数组
const array = [1,2,3,4];
const arrayCopy = array.concat(['哈哈','哇哇']);
console.log(arrayCopy); // [1, 2, 3, 4, '哈哈', '哇哇'] -
合并多个值和数组
const array = [1, 2, 3, 4];
const arrayCopy = array.concat(["哈哈", "哇哇"], "哈哈", "哇哇");
console.log(arrayCopy); // [1, 2, 3, 4, '哈哈', '哇哇', '哈哈', '哇哇']
原理
Array.prototype.copyWithin()
Array.prototype.copyWithin() 浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。
语法
arr.copyWithin(target[, start[, end]])
- target: 0 为基底的索引,复制序列到该位置。如果是负数,target 将从末尾开始计算。如果 target 大于等于 arr.length,将会不发生拷贝。如果 target 在 start 之后,复制的序列将被修改以符合 arr.length。
- start: 0 为基底的索引,开始复制元素的起始位置。如果是负数,start 将从末尾开始计算。如果 start 被忽略,copyWithin 将会从0开始复制。
- 如果
start < 0
,则start = 数组长度+start
- 如果
- end: 0 为基底的索引,开始复制元素的结束位置。copyWithin 将会拷贝到该位置,但不包括 end 这个位置的元素。如果是负数, end 将从末尾开始计算。如果 end 被忽略,copyWithin 方法将会一直复制至数组结尾(默认为 arr.length)。
- 如果
end < 0
,则end = 数组长度+end
- 如果
返回值
改变后的数组。
应用
-
拷贝数组
const array = [1, 2, 3, 4];
const arrayCopy = array.copyWithin(3,0,2);
console.log(array); // [1, 2, 3, 1]
console.log(arrayCopy); // [1, 2, 3, 1]
原理(Polyfill)
Array.prototype.copyWithin = function(target,start,end){
if(this == null){
throw new TypeError('this is null or not defined');
}
var object = Object(this);
var length = object.length >>> 0;
var targetCopy = target >> 0;
targetCopy = targetCopy < 0 ? Math.max(length+targetCopy,0):Math.min(targetCopy,length);
var startCopy = start >> 0;
startCopy = startCopy < 0 ? Math.max(length+startCopy,0):Math.min(startCopy,length);
var endCopy = end === undefined ? length : end >> 0;
endCopy = endCopy<0 ? Math.max(length+endCopy,0):Math.min(endCopy,length);
var count = Math.min(endCopy - startCopy,length - targetCopy);
var direction = 1;
if(startCopy < targetCopy && targetCopy < (startCopy + count)){
direction = -1;
startCopy += count -1;
targetCopy += count -1 ;
}
while(count > 0){
if(startCopy in object){
object[targetCopy] = object[startCopy];
}else{
delete object(targetCopy);
}
startCopy += direction;
targetCopy += direction;
count --;
}
return object;
}
var array = [1,2,3,4,5,6];
array.copyWithin(2,0);
console.log(array);
Array.prototype.entries()
Array.prototype.entries() 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。
语法
arr.entries()
返回值
一个新的 Array 迭代器对象。Array Iterator是对象,它的原型(proto:Array Iterator)上有一个next方法,可用用于遍历迭代器取得原数组的[key,value]。
应用
-
运行迭代器: 注意以下几点
-
**对于迭代器.next()**的返回值:
{ value: Array(2), done: false }
-
next.done用于指示迭代器是否完成:在每次迭代时进行更新而且都是false,直到迭代器结束done才是true。
-
next.value是一个
["key","value"]
的数组,是返回的迭代器中的元素值。
-
-
对于遍历次数 应该是
[0,length+1)
。因为遍历length+1
次才可以遍历完毕。
var array = [1, 2, 3, 4, 5, 6];
var iterator = array.entries();
for (var i = 0; i < array.length + 1; i++) {
var item = iterator.next();
console.log(item); // {value: Array(2), done: false} {value: Array(2), done: false} …… {value: Array(2), done: false} {value: undefined, done: true}
console.log(item.value); // [0, 1] [1, 2] …… [5, 6] undefined
if (item.done !== true) {
console.log(item.value[1]); // 1 2 3 4 5 6
}
} -
原理
Array.prototype.every()
Array.prototype.every() 方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。Array.prototype.every() 和数学中的所有类似,当所有的元素都符合条件才会返回true。正因如此,若传入一个空数组,无论如何都会返回true。
[].some()
与 [].every()
的区别:
[].some()
无论如何都会返回false
[].every()
无论如何都会返回true
语法
arr.every(callback(element[, index[, array]])[, thisArg])
- callback: 用来测试每个元素的函数,它可以接收三个参数:
- element: 用于测试的当前值。
- index: 用于测试的当前值的索引。
- array: 调用 every 的当前数组。
- thisArg: 执行 callback 时使用的 this 值。
返回值
如果回调函数的每一次返回都为 true 值,返回 true ,否则返回 false。
应用
-
检测所有元素是否都大于10
const array = [1,2,3,4,5,11,12,13];
console.log(array.every(function(item,index,array){
return item >= 10;
})); // false
原理
Array.prototype.every = function (callback, thisArg) {
if (this == null) {
throw new TypeError("this is null or not defined");
}
if (typeof callback !== "function") {
throw new TypeError("callback is not function");
}
var object = Object(this);
var length = object.length >>> 0;
var index = 0;
while (index < length) {
if (index in object) {
var value = object[index];
var result = callback.call(thisArg, value, index, object);
if (!result) {
return false;
}
}
index++;
}
return true;
};
const array = [1, 2, 3, 4, 5, 11, 12, 13];
console.log(
array.every(function (item, index, array) {
return item >= 10;
})
); // false
Array.prototype.fill()
Array.prototype.fill() 方法用一个固定值填充一个数组 中从起始索引到终止索引内的全部元素。不包括终止索引。
语法
arr.fill(value[, start[, end]])
- value: 用来填充数组元素的值
- start: 起始索引,默认值为0
- 如果
start<0
,则start = 数组长度 + start
- 如果
- end: 终止索引,默认值为this.length
- 如果
end<0
,则start = 数组长度 + end
- 如果
返回值
修改后的数组。
应用
-
对象批量添加属性: 通过
call
改变Array.prototype.fill
的this
指针方可实现const obj = {
length:3
}
Array.prototype.fill.call(obj,'哈哈')
console.log(obj); // {0: '哈哈', 1: '哈哈', 2: '哈哈', length: 3} -
为数组填充引用类型: fill的参数为引用类型,会导致都执行同一个引用类型
const array = new Array(10);
array.fill({});
array[0].name = 'a0';
console.log(array[1],array[9]); // {name: 'a0'} {name: 'a0'}
原理(Polyfill)
Array.prototype.fill = function(value,start,end){
if(this == null){
throw new TypeError('this is null or undefined');
}
var object = Object(this);
var length = object.length >>> 0;
var startCopy = start >> 0;
startCopy = startCopy < 0 ? Math.max(startCopy+length,0):Math.min(startCopy,length);
var endCopy = end === undefined ? length : end >> 0;
endCopy = endCopy < 0 ? Math.max(endCopy+length,0):Math.min(endCopy,length);
while(startCopy < endCopy){
object[startCopy++] = value;
}
return object;
}
const array1 = new Array(10);
array1.fill(10);
console.log(array1);
const array2 = new Array(10);
array2.fill(10, -4);
console.log(array2);
const array3 = new Array(10);
array3.fill(10, -4, 12);
console.log(array3);
Array.prototype.find()
Array.prototype.find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
语法
arr.find(callback[, thisArg])
- callback: 在数组每一项上执行的函数,接收 3 个参数:
- element: 当前遍历到的元素。
- index可选: 当前遍历到的索引。
- array可选: 数组本身。
- thisArg可选: 执行回调时用作this 的对象。
返回值
数组中第一个满足所提供测试函数的元素的值,否则返回 undefined。
应用
-
查找名字叫
柏拉图
的元素var array = [
{
name:'柏拉图'
},
{
name:'柏拉文'
}
]
var item = array.find(function(value,index,array){
return value.name === '柏拉图'
});
console.log(item); // array.html:22 {name: '柏拉图'}
原理(Polyfill)
Array.prototype.find = function(callback,thisArg){
if(this == null){
throw new TypeError('this is null or not defined');
}
if(typeof callback !== 'function'){
throw new TypeError('callback is not function');
}
var object = Object(this);
var length = object.length >>> 0;
var index = 0;
while(index < length){
var value = object[index];
var result = callback.call(thisArg,value,index,object);
if(result){
return value;
}
index++;
}
return undefined;
}
var array = [
{
name:'柏拉图'
},
{
name:'柏拉文'
}
]
var item = array.find(function(value,index,array){
return value.name === '柏拉图'
});
console.log(item); // array.html:22 {name: '柏拉图'}
Array.prototype.findIndex()
**Array.prototype.findIndex()**方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。
语法
arr.findIndex(callback[, thisArg])
- callback: 针对数组中的每个元素, 都会执行该回调函数, 执行时会自动传入下面三个参数:
- element: 当前元素。
- index: 当前元素的索引。
- array: 调用findIndex的数组。
- thisArg可选: 执行callback时作为this对象的值。
返回值
数组中通过提供测试函数的第一个元素的索引。否则,返回-1
应用
-
查找名字叫
柏拉图
的元素var array = [
{
name: "柏拉图",
},
{
name: "柏拉文",
},
];
var index = array.findIndex(function (value, index, array) {
return value.name === "柏拉图";
});
console.log(index); // 0
原理(Polyfill)
Array.prototype.findIndex = function (callback, thisArg) {
if (this == null) {
throw new TypeError("this is null or not defined");
}
if (typeof callback !== "function") {
throw new TypeError("callback is not function");
}
var object = Object(this);
var length = object.length >>> 0;
var index = 0;
while (index < length) {
var value = object[index];
var result = callback.call(thisArg, value, index, object);
if (result) {
return index;
}
index++;
}
return -1;
};
var array = [
{
name: "柏拉图",
},
{
name: "柏拉文",
},
];
var index = array.findIndex(function (value, index, array) {
return value.name === "柏拉图";
});
console.log(index); // 0
Array.prototype.flat()
Array.prototype.flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
语法
var newArray = arr.flat([depth])
- depth 可选: 指定要提取嵌套数组的结构深度,默认值为 1。
返回值
一个包含将数组与子数组中所有元素的新数组。
应用
-
扁平化嵌套数组
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
//使用 Infinity,可展开任意深度的嵌套数组
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -
利用扁平化移除数组空项
var arr4 = [1, 2, , 4, 5];
arr4.flat();
// [1, 2, 4, 5]
替代方案
-
使用扩展运算符实现一层扁平
function flat(array){
return [].concat(...array);
}
const array = [1,[2,[3,4,[5,6,7],8,9],10,11],12,13,14,[15,[16]]];
console.log(flat(array)); // [1, 2, Array(5), 10, 11, 12, 13, 14, 15, Array(1)] -
使用
reduce
与concat
实现一层扁平function flat(array){
return array.reduce(function(accumulator,currentValue,arr){
return accumulator.concat(currentValue);
},[]);
}
const array = [1,[2,[3,4,[5,6,7],8,9],10,11],12,13,14,[15,[16]]];
console.log(flat(array)); // [1, 2, Array(5), 10, 11, 12, 13, 14, 15, Array(1)] -
使用
reduce
+concat
递归实现深层扁平完整写法function flat(array, deep = 1) {
if (deep > 0) {
return array.reduce(function (accumulator, currentValue, arr) {
if (Array.isArray(currentValue)) {
return accumulator.concat(flat(currentValue, deep - 1));
} else {
return accumulator.concat(currentValue);
}
}, []);
} else {
return array.slice();
}
}
const array = [
1,
[2, [3, 4, [5, 6, 7], 8, 9], 10, 11],
12,
13,
14,
[15, [16]],
];
console.log(flat(array, 2)); // [1, 2, 3, 4, Array(3), 8, 9, 10, 11, 12, 13, 14, 15, 16]
console.log(flat(array, Infinity)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]function flat(array, deep = 1) {
return deep > 0
? array.reduce(
(accumulator, currentValue, arr) =>
Array.isArray(currentValue)
? accumulator.concat(flat(currentValue, deep - 1))
: accumulator.concat(currentValue),
[]
)
: array.slice();
}
const array = [
1,
[2, [3, 4, [5, 6, 7], 8, 9], 10, 11],
12,
13,
14,
[15, [16]],
];
console.log(flat(array, 2)); // [1, 2, 3, 4, Array(3), 8, 9, 10, 11, 12, 13, 14, 15, 16]
console.log(flat(array,Infinity)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] -
使用
forEach
递归实现深层扁平function flat(array, deep = 1) {
const result = [];
const recurse = (currentArray,currentDeep)=>{
currentArray.forEach(function(value,index,arr){
if(Array.isArray(value) && currentDeep > 0){
recurse(value,currentDeep-1);
}else{
result.push(value);
}
});
}
recurse(array,deep);
return result;
}
const array = [
1,
[2, [3, 4, [5, 6, 7], 8, 9], 10, 11],
12,
13,
14,
[15, [16]],
];
console.log(flat(array, 2)); // [1, 2, 3, 4, Array(3), 8, 9, 10, 11, 12, 13, 14, 15, 16]
console.log(flat(array, Infinity)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] -
使用堆栈 循环迭代实现深层扁平
function flat(array) {
const stack = [...array];
const result = [];
while(stack.length){
const value = stack.pop();
if(Array.isArray(value)){
stack.push(...value);
}else{
result.push(value);
}
}
return result.reverse();
}
const array = [
1,
[2, [3, 4, [5, 6, 7], 8, 9], 10, 11],
12,
13,
14,
[15, [16]],
];
console.log(flat(array, 2)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
console.log(flat(array, Infinity)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] -
使用
Generator
循环迭代实现深层扁平function* flat(array) {
for(let item of array){
if(Array.isArray(item)){
yield* flat(item);
}else{
yield item;
}
}
}
const array = [
1,
[2, [3, 4, [5, 6, 7], 8, 9], 10, 11],
12,
13,
14,
[15, [16]],
];
console.log([...flat(array, 2)]); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
console.log([...flat(array, Infinity)]); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
Array.prototype.flatMap()
flatMap()Array.prototype.flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与map连着深度值为1的flat几乎相同,但flatMap通常在合并成一种方法的效率稍微高一些。
语法
var new_array = arr.flatMap(function callback(currentValue[, index[, array]]) {
// return element for new_array
}[, thisArg])
- callback: 可以生成一个新数组中的元素的函数,可以传入三个参数:
- currentValue: 当前正在数组中处理的元素
- index: 可选的。数组中正在处理的当前元素的索引。
- array: 可选的。被调用的 map 数组
- thisArg: 可选的。执行 callback 函数时 使用的this 值。
返回值
一个新的数组,其中每个元素都是回调函数的结果,并且结构深度depth值为1。
应用
-
将元素转化为数组
const array = [1,2,3,4,5,6,7,8];
const arrayCopy = array.flatMap(function(value,index,arr){
return [[value*2]]
});
console.log(arrayCopy); // [Array(1), Array(1), Array(1), Array(1), Array(1), Array(1), Array(1), Array(1)]
原理
Array.from()
Array.from() 方法对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。**Array.from()**可以通过以下方式来创建数组对象:
- 伪数组对象(拥有一个 length 属性和若干索引属性的任意对象)
- 可迭代对象(可以获取对象中的元素,如 Map和 Set 等)
语法
Array.from(arrayLike[, mapFn[, thisArg]])
- arrayLike: 想要转换成数组的伪数组对象或可迭代对象。
- mapFn: 如果指定了该参 数,新数组中的每个元素会执行该回调函数。
Array.from()
方法有一个可选参数 mapFn,让你可以在最后生成的数组上再执行一次map法后再返回。也就是说Array.from(obj, mapFn, thisArg)
就相当于Array.from(obj).map(mapFn, thisArg)
- thisArg: 可选参数,执行回调函数 mapFn 时 this 对象。
返回值
一个新的数组实例。
应用
-
从
String
生成数组const result = Array.from('柏拉图');
console.log(result); // ['柏', '拉', '图'] -
从
Set
生成数组const set = new Set(['柏','拉','图']);
const result = Array.from(set);
console.log(result); // ['柏', '拉', '图'] -
从
Map
生成数组const map = new Map([['name','名字'],['age','年龄']]);
const result = Array.from(map);
console.log(result); // [Array(2), Array(2)]
原理(Polyfill)
无法使用Polyfill实现真正的的迭代器,该实现不支持规范中定义的泛型可迭代元素。以下实现只支持类数组。
function createArrayLike (a,b,c,d,e,f,g){
return arguments;
}
Array.from = function(arrayLike,mapCallback,thisArg){
if(arrayLike == null){
throw new TypeError('Array.from: the first argument must be a array-like');
}
if(mapCallback !==undefined && Object.prototype.toString.call(mapCallback) !== "[object Function]"){
throw new TypeError('Array.from: the second argument must be a function');
}
var object = Object(arrayLike);
var length = object.length >>> 0;
var result = new Array(length);
var index = 0;
while(index < length){
var value = object[index];
if(mapCallback){
result[index++] = mapCallback.call(thisArg,value,index);
}else{
result[index++] = value;
}
}
result.length = index;
return result;
}
const arrayLike = createArrayLike(1,2,3,4,5,6,7);
console.log(arrayLike); // Arguments(7) [1, 2, 3, 4, 5, 6, 7, callee: ƒ, Symbol(Symbol.iterator): ƒ]
const result = Array.from(arrayLike,function(value,index){
return value+'哈哈'
});
console.log(result); // ['1哈哈', '2哈哈', '3哈哈', '4哈哈', '5哈哈', '6哈哈', '7哈哈']
Array.prototype.includes()
Array.prototype.includes() 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回 false。Array.prototype.includes() 判断两值相等的算法为sameValueZero
算法。
Array.prototype.indexOf()
与 Array.prototype.includes()
在底层中判断两值相等的算法区别:
-
Array.prototype.indexOf()
与===
算法一致 -
Array.prototype.includes()
为sameValueZero
算法
语法
arr.includes(valueToFind[, fromIndex])
-
valueToFind
: 需要查找的元素值。 -
fromIndex
: 从fromIndex
索引处开始查找valueToFind
。fromIndex >= 数组长度
,直接返回false0 <= fromIndex < 数组长度
,从fromIndex
处开始搜索fromIndex < 0
,计算数组长度 + fromIndex
的值- 如果计算出的值小于
0
,从索引值为0
的位置开始搜索 - 如果计算出的值大于
0
, 从计算出的位置处开始搜索
- 如果计算出的值小于
返回值
返回一个布尔值 Boolean 。
对比
-
Array.prototype.includes()
与Array.prototype.indexOf()
有什么区别?-
indexOf
比较两个值的时候只使用了===
,所以NaN
不可以检测 -
includes
比较两个值的时候内部使用了sameValueZero
算法 即x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y))
可以检测到NaN
const array = [NaN];
console.log(array.indexOf(NaN)); // -1
console.log(array.includes(NaN)); // true -