TIPS
# Array属性
Array.lengthArray构造函数的length属性,其值为1(注意该属性为静态属性,不是数组实例的length属性)。get Array[@@species]返回
Array构造函数,Array[Symbol.species]; // function Array()。Array.prototype通过数组的原型对象可以为所有数组对象添加属性,鲜为人知的事实:
Array.prototype本身也是一个Array。
# Array方法
Array.from()从类数组对象或者可迭代对象中创建一个新的数组实例。
Array.from(arrayLike[, mapFn[, thisArg]])Array.isArray()用来判断某个变量是否是一个数组对象。
Array.isArray(Array.prototype); // trueArray.of()根据一组参数来创建新的数组实例,支持任意的参数数量和类型。
Array.of()和Array构造函数之间的区别在于处理整数参数:Array.of(7)创建一个具有单个元素7的数组,而Array(7)创建一个长度为7的空数组(注意:这是指一个有7个空位(empty)的数组,而不是由7个undefined组成的数组)。
# 数组实例属性
Array.prototype.constructor所有的数组实例都继承了这个属性,它的值就是
Array,表明了所有的数组都是由Array构造出来的。Array.prototype.length上面说了,因为
Array.prototype也是个数组,所以它也有length属性,这个值为0,因为它是个空数组(但是有其他属性)。
# 数组实例方法
# 修改器方法
WARNING
下面的这些方法会改变调用它们的对象自身的值
Array.prototype.copyWithin()- 描述:浅复制数组的一部分到同一数组中的另一个位置,覆盖原有的值,并返回它,不会改变原数组的长度。
- 语法:
arr.copyWithin(target[, start[, end]])。 - 返回值:改变后的数组。
Array.prototype.fill()- 描述:用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。
- 语法:
arr.fill(value[, start[, end]])。 - 返回值:修改后的数组。
Array.prototype.shift()- 描述:从数组中删除第一个元素,并返回该元素的值。
- 语法:
arr.shift()。 - 返回值:从数组中删除的元素,如果数组为空则返回
undefined。
Array.prototype.unshift()- 描述:将一个或多个元素添加到数组的开头,并返回该数组的新长度。
- 语法:
arr.unshift(element1, ..., elementN)。 - 返回值:新的
length属性值。
Array.prototype.pop()- 描述:从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。
- 语法:
arr.pop()。 - 返回值:从数组中删除的元素,如果数组为空则返回
undefined。
Array.prototype.push()- 描述:将一个或多个元素添加到数组的末尾,并返回该数组的新长度。
- 语法:
arr.push(element1, ..., elementN)。 - 返回值:新的
length属性值。
Array.prototype.reverse()- 描述:将数组中元素的位置颠倒,并返回该数组。
- 语法:
arr.reverse()。 - 返回值:颠倒后的数组。
Array.prototype.sort()- 描述:用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后按照它们的UTF-16码元值升序排序。
- 语法:
arr.sort([compareFunction])。 - 返回值:排序后的数组。
Array.prototype.splice()- 描述:通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。
- 语法:
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])。 - 返回值:一个包含了删除的元素的数组。
# 访问方法
WARNING
下面的这些方法绝对不会改变调用它们的对象的值,只会返回一个新的数组或者返回一个其它的期望值。
Array.prototype.concat()- 描述:用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
- 语法:
var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])。 - 返回值:新的
Array实例。
Array.prototype.includes()- 描述:用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回
true,否则返回false。 - 语法:
arr.includes(valueToFind[, fromIndex])。 - 返回值:返回一个布尔值,如果在数组中找到了(如果传入了
fromIndex,表示在fromIndex指定的索引范围中找到了)则返回true。
- 描述:用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回
Array.prototype.join()- 描述:将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。
- 语法:
arr.join([separator])。 - 返回值:一个所有数组元素连接的字符串。如果
arr.length为0,则返回空字符串。如果一个元素为undefined或null,它会被转换为空字符串。
Array.prototype.slice()- 描述:返回一个新的数组对象,这一对象是一个由
begin和end决定的原数组的浅拷贝(包括begin,不包括end)。 - 语法:
arr.slice([begin[, end]])。 - 返回值:一个含有被提取元素的新数组。
- 描述:返回一个新的数组对象,这一对象是一个由
Array.prototype.toString()- 描述:返回一个字符串,表示指定的数组及其元素。
- 语法:
arr.toString()。 - 返回值:一个表示指定的数组及其元素的字符串,其中包含用逗号分隔的每个数组元素。如果
join方法不可用或者不是函数,则会使用Object.prototype.toString来代替,并返回[object Array]。
Array.prototype.toLocaleString()- 描述:返回一个字符串表示数组中的元素。数组中的元素将使用各自的
toLocaleString方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号“,”)隔开。 - 语法:
arr.toLocaleString([locales[,options]]);。 - 返回值:表示数组元素的字符串。
- 描述:返回一个字符串表示数组中的元素。数组中的元素将使用各自的
Array.prototype.indexOf()- 描述:返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。
- 语法:
arr.indexOf(searchElement[, fromIndex])。 - 返回值:首个被找到的元素在数组中的索引位置,若没有找到则返回-1。
Array.prototype.lastIndexOf()- 描述:返回指定元素在数组中的最后一个的索引,如果不存在则返回-1。从数组的后面向前查找,从
fromIndex处开始。 - 语法:
arr.lastIndexOf(searchElement[, fromIndex])。 - 返回值:数组中该元素最后一次出现的索引,如未找到返回-1。
- 描述:返回指定元素在数组中的最后一个的索引,如果不存在则返回-1。从数组的后面向前查找,从
Array.prototype.toSource()非标准- 描述:返回一个字符串,代表该数组的源代码。
- 语法:
array.toSource()。 - 返回值:返回一个字符串。
TIPS
有索引参数方法总结
copyWithinfillspliceincludessliceindexOflastIndexOf
- 如果索引值
index大于0,没有任何特殊含义,就是指定匹配位置,如果是超出数组长度则表示能匹配到数组的结尾。 - 如果索引值
index小于0,则表示从数组末位开始的第几位(从-1计数,这意味着-n是倒数第n个元素并且等价于array.length - n)。如果负数的绝对值大于数组的长度,则表示能匹配到数组开始的0位。 - 如果传入的索引是一个区间,
start和end,那么能取到的值都是左闭右开的:[start, end),即都是取不到end位处的元素,例如copyWithin、fill、slice,splice不同的是传入的是开始索引和截取元素的个数。
# 迭代方法
WARNING
在每一个数组元素都分别执行完回调函数之前,数组的length属性会被缓存在某个地方,所以,如果你在回调函数中为当前数组添加了新的元素,那么那些新添加的元素是不会被遍历到的。此外,如果在回调函数中对当前数组进行了其它修改,比如改变某个元素的值或者删掉某个元素,那么随后的遍历操作可能会受到未预期的影响。
Array.prototype.forEach()- 描述:对数组的每个元素执行一次给定的函数。
- 语法:
arr.forEach(callback(element[, index[, array]])[, thisArg])。 - 返回值:
undefined。
Array.prototype.map()- 描述:创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。
- 语法:
var newArray = arr.map(callback(element[, index[, array]]){ return element }[, thisArg])。 - 返回值:一个由原数组每个元素执行回调函数的结果组成的新数组。如果被
map调用的数组是离散的,新数组将也是离散的保持相同的索引为空。
Array.prototype.every()- 描述:测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。若收到一个空数组,此方法在一切情况下都会返回 true。
- 语法:
arr.every(callback(element[, index[, array]])[, thisArg])。 - 返回值:如果回调函数的每一次返回都为
truthy值,返回true,否则返回false。
Array.prototype.some()- 描述:测试数组中是不是至少有1个元素通过了被提供的函数测试。如果用一个空数组进行测试,在任何情况下它返回的都是
false。 - 语法:
arr.some(callback(element[, index[, array]])[, thisArg])。 - 返回值:数组中有至少一个元素通过回调函数的测试就会返回
true;所有元素都没有通过回调函数的测试返回值才会为false。
- 描述:测试数组中是不是至少有1个元素通过了被提供的函数测试。如果用一个空数组进行测试,在任何情况下它返回的都是
Array.prototype.filter()- 描述:创建一个新数组,其包含通过所提供函数实现的测试的所有元素。
- 语法:
var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])。 - 返回值:一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。
Array.prototype.find()- 描述:返回数组中满足提供的测试函数的第一个元素的值。否则返回
undefined。 - 语法:
arr.find(callback(element[, index[, array]])[, thisArg])。 - 返回值:数组中第一个满足所提供测试函数的元素的值,否则返回
undefined。
- 描述:返回数组中满足提供的测试函数的第一个元素的值。否则返回
Array.prototype.findIndex()- 描述:返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。
- 语法:
arr.findIndex(callback(element[, index[, array]])[, thisArg])。 - 返回值:数组中通过提供测试函数的第一个元素的索引。否则,返回-1
Array.prototype.reduce()- 描述:对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
- 语法:
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])。 - 返回值:函数累计处理的结果。
Array.prototype.reduceRight()- 描述:接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。
- 语法:
arr.reduceRight(callback(accumulator, currentValue[, index[, array]])[, initialValue])。 - 返回值:函数累计处理的结果。
Array.prototype.entries()- 描述:返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。
- 语法:
arr.entries()。 - 返回值:一个新的
Array迭代器对象。
Array.prototype.keys()- 描述:返回一个包含数组中每个索引键的Array Iterator对象。索引迭代器会包含那些没有对应元素的索引。
- 语法:
arr.keys()。 - 返回值:一个新的
Array迭代器对象。
Array.prototype.values()- 描述:返回一个新的Array Iterator对象,该对象包含数组每个索引的值。
- 语法:
arr.values()。 - 返回值:一个新的
Array迭代对象。 Array.prototype.values是Array.prototype[Symbol.iterator]的默认实现。Array.prototype.values === Array.prototype[Symbol.iterator] // true。
Array.prototype[@@iterator]()- 描述:
@@iterator属性和Array.prototype.values()属性的初始值是同一个函数对象。 - 语法:
arr[Symbol.iterator]()。 - 返回值:数组的
iterator方法,默认情况下,与values()返回值相同,arr[Symbol.iterator]则会返回values()函数。
- 描述:
# 迭代方法小结
forEach、every、some、filter、find、findIndex、map接收的callback参数都是一样callback(element[, index[, array]],并且第二个参数都是执行回调时用作this的对象thisArg,reduce和reduceRight参数是一样的,一个reducer函数和一个初始值。thisArg参数(this),每次调用时,它都被传给callback函数,作为它的this值。注意:如果使用箭头函数表达式来传入函数参数,thisArg参数会被忽略,因为箭头函数在词法上绑定了this值。所有的迭代方法都不会直接改变调用它的对象,但是那个对象可能会被
callback函数改变。EMCA语言规范:'forEach does not directly mutate the object on which it is called but the object may be mutated by the calls to callbackfn.'
对于
find和findIndex,callback函数会为数组中的每个索引调用即从0到length - 1,而不仅仅是那些被赋值的索引,这意味着对于稀疏数组来说,该方法的效率要低于那些只遍历有值的索引的方法。除开这两个之外的迭代方法在执行callback时都会跳过未被赋值的索引(直接修改索引操作造成的empty值或者使用delete删除的值)。对于map,虽然会跳过未被赋值的索引,但是最后得到的结果数组依旧保持了原有的未被赋值的索引。
# 其他
Array.prototype.at()- 描述:接受整数值并返回该索引处的项,允许正整数和负整数。负整数从数组中的最后一项开始倒数。
- 语法:
arr.at(index)。 - 返回值:该索引处的项。
[1, 2, 3].at(-1); // 3。
Array.prototype.flat()- 描述:按照一个可指定的深度(默认值为1)递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
- 语法:
var newArray = arr.flat([depth])。 - 返回值:一个包含将数组与子数组中所有元素的新数组。
Array.prototype.flatMap()- 描述:
flatMap()方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。flatMap方法与map方法和深度depth为1的flat几乎相同,但flatMap通常在合并成一种方法的效率稍微高一些。 - 语法:
var new_array = arr.flatMap(function callback(currentValue[, index[, array]]) { // return element for new_array}[, thisArg]) - 返回值:一个新的数组,其中每个元素都是回调函数的结果,并且结构深度depth值为1。
- 描述:
# 手动实现部分方法
# forEach
if (!Array.prototype.forEach) {
Array.prototype.forEach = 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 a function`);
}
// 抽象操作ToObject将其参数转换为Object类型的值
// 个人目前发现是可以防止其他非对象值在后面使用in时报错
// 但是不清楚真正目的
const O = Object(this);
// O.length >>> 0 无符号右移 0 位,保证转换后的值为正整数。其实底层做了 2 层转换,
// 第一是非 number 转成 number 类型,第二是将 number 转成 Uint32 类型。
const length = O.length >>> 0;
let k = 0;
while (k < length) {
// 使用 in 来判断索引 确保能够跳过那些empty的位
if (k in O) {
// thisArg 没传就是 undefined
callback.call(thisArg, O[k], k, O);
}
k++;
}
// return undefined
};
}
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
# map
if (!Array.prototype.map) {
Array.prototype.map = 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 a function`);
}
// 抽象操作ToObject将其参数转换为Object类型的值
const O = Object(this);
// O.length >>> 0 无符号右移 0 位,保证转换后的值为正整数。其实底层做了 2 层转换,
// 第一是非 number 转成 number 类型,第二是将 number 转成 Uint32 类型。
const length = O.length >>> 0;
let k = 0;
// 这样保证了原来是empty的位,map后还是empty
const mapResult = new Array(length);
while (k < length) {
if (k in O) {
mapResult[k] = callback.call(thisArg, O[k], k, O);
}
k++;
}
return mapResult;
};
}
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
# reduce
// redecuRight 原理差不多只是遍历索引从右往左
if (!Array.prototype.reduce) {
Array.prototype.reduce = function (callback, initialValue) {
if (this == null) {
throw new TypeError('this is null or not defined');
}
if (typeof callback !== 'function') {
throw new TypeError(`${callback} is not a function`);
}
// 抽象操作ToObject将其参数转换为Object类型的值
const O = Object(this);
// O.length >>> 0 无符号右移 0 位,保证转换后的值为正整数。其实底层做了 2 层转换,
// 第一是非 number 转成 number 类型,第二是将 number 转成 Uint32 类型。
const length = O.length >>> 0;
let k = 0;
let value;
if (arguments.length >= 2) {
// 传了初始值
value = initialValue;
} else {
// 找到一个非empty的有效值
while (k < length && !(k in O)) {
k++;
}
if (k >= length) {
throw new TypeError('Reduce of empty array with no initial value');
}
value = O[k];
// 用了数组中的一个初始值 那么累加的从下一个开始
k++;
}
while (k < length) {
if (k in O) {
value = callback(value, O[k], k, O);
}
k++;
}
return value;
};
}
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
34
35
36
37
38
39
40
41
42
43
44
# flat
if (!Array.prototype.flat) {
Array.prototype.flat = function (depth = 1) {
if (this == null) {
throw new TypeError('this is null or not defined');
}
const result = []; // 缓存递归结果
// 开始递归
(function flat(_arr, _depth) {
// forEach 遍历数组会自动跳过空元素
_arr.forEach((item) => {
// 控制递归深度
if (Array.isArray(item) && _depth > 0) {
// 递归数组
flat(item, _depth - 1);
} else {
// 缓存元素
result.push(item);
}
});
}(this, depth));
// 返回递归结果
return result;
};
}
// function flatten(arr) {
// while (arr.some((item) => Array.isArray(item))) {
// arr = [].concat(...arr);
// // concat接收的值可以是数组/值,如果是数据类型如字符串,数字和布尔
// // concat将字符串和数字的值复制到新数组中
// }
// return arr;
// }
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