JS-数组
本文章讲解JavaScript的数组类型。
参考:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array
https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/First_steps/Arrays
静态方法
1、Array.from()
Array.from()方法对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
语法
Array.from(arrayLike[, mapFn[, thisArg]])
arrayLike
想要转换成数组的伪数组对象或可迭代对象。
mapFn 可选
如果指定了该参数,新数组中的每个元素会执行该回调函数。
thisArg 可选
可选参数,执行回调函数 mapFn 时 this 对象。
Array.from(obj, mapFn, thisArg) 就相当于 Array.from(obj).map(mapFn, thisArg)
实例参考https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/from
里面居然还有序列生成器和去重合并
2、Array.isArray()
判断是不是数组
语法,返回true或者false
Array.isArray(obj)
鲜为人知的事实:其实 Array.prototype 也是一个数组。(有趣)
当检测Array实例时, Array.isArray 优于 instanceof,因为Array.isArray能检测iframes。
3、Array.of()
Array.of() 和 Array 构造函数之间的区别在于处理整数参数:Array.of(7) 创建一个具有单个元素 7 的数组,而 Array(7) 创建一个长度为7的空数组(**注意:**这是指一个有7个空位(empty)的数组,而不是由7个undefined组成的数组)。
Array.of(7); // [7]
Array.of(1, 2, 3); // [1, 2, 3]
Array(7); // [ , , , , , , ]
Array(1, 2, 3); // [1, 2, 3]
方法
1、字符串和数组互换
let myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';
// 通过逗号分隔来转换成数组
let myArray = myData.split(',');
// 再将数组通过逗号合并成字符串,或者通过toString(),但是更受限制
let myNewString = myArray.join(',');
2、添加和删除数组项
**push(**可以放一个或者多个元素)。返回该数组的新长度(该方法修改原有数组)
pop() 删除最后一个元素。返回该数组的最后一个元素(该方法修改原有数组)
unshift 添加元素到开始,返回该数组的新长度(该方法修改原有数组)
shift() 删除第一个元素,并返回该元素的值(该方法修改原有数组)
3、找出某个元素在数组中的索引
indexOf() ,返回第一个给顶元素的第一个索引,不存在返回-1
arr.indexOf(searchElement[, fromIndex])
let pos = fruits.indexOf('Banana')
lastIndexOf() 方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从 fromIndex 处开始。
查找所有的元素和indexOf的差别就是在对待0这个元素的处理,如果为0,那么fromIndex就是-1,-1就又重新开始往前找,会进入无限循环,直接炸了。
var indices = [];
var array = ['a', 'b', 'a', 'c', 'a', 'd'];
var element = 'a';
var idx = array.lastIndexOf(element);
while (idx != -1) {
indices.push(idx);
idx = (idx > 0 ? array.lastIndexOf(element, idx - 1) : -1);
}
console.log(indices);
// [4, 2, 0];
4、通过索引删除元素
splice()
let removedItem = fruits.splice(pos, 1)
5、复制一个数组slice
slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。
arr.slice([begin[, end]])
如果 begin 超出原数组的索引范围,则会返回空数组。
如果 end 大于数组的长度,slice 也会一直提取到原数组末尾。
6、合并数组
concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。返回一个浅拷贝,也就是对象返回的是引用,数据类型如字符串,数字和布尔是复制到新数组中。(如果里面是还是一个数组,那么也是引用,比如二维数组合并)
7、浅拷贝自我复制
copyWithin() 方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。会改变原来的数组。
arr.copyWithin(target[, start[, end]])
target
0 为基底的索引,复制序列到该位置。如果是负数,target 将从末尾开始计算。
如果 target 大于等于 arr.length,将会不发生拷贝。如果 target 在 start 之后,复制的序列将被修改以符合 arr.length。
start
0 为基底的索引,开始复制元素的起始位置。如果是负数,start 将从末尾开始计算。
如果 start 被忽略,copyWithin 将会从0开始复制。
end
0 为基底的索引,开始复制元素的结束位置。copyWithin 将会拷贝到该位置,但不包括 end 这个位置的元素。如果是负数, end 将从末尾开始计算。
如果 end 被忽略,copyWithin 方法将会一直复制至数组结尾(默认为 arr.length)。
8、返回迭代器
entries() 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。
9、very
every() 方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。
注意:若收到一个空数组,此方法在一切情况下都会返回 true。
function isBigEnough(element, index, array) {
return element >= 10;
}
[12, 5, 8, 130, 44].every(isBigEnough); // false
[12, 54, 18, 130, 44].every(isBigEnough); // true
[12, 54, 18, 130, 44].every(x => x >= 10); // true
对应的会有个some
some() 方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。
10、填充
fill() 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。
arr.fill(value[, start[, end]])
value
用来填充数组元素的值。
start 可选
起始索引,默认值为0。
end 可选
终止索引,默认值为 this.length。
注意:如果fill的参数为引用类型,会导致都执行都一个引用类型
这个很奇怪,好像把数组转换成了对象。
[].fill.call({ length: 3 }, 4); // {0: 4, 1: 4, 2: 4, length: 3}
11、filter
filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
有点像every,只不过那个判断是不是满足,而这个是选出所有满足的元素并创建成新的数组。
这个蛮实用的,可以看看这个实例
12、find
find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回undefined。
findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。
13、flat扁平化数组
flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。会删除数组中的空项。
语法
var newArray = arr.flat([depth])
//使用 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]
这个方法有点新,可以用reduce和concat进行替换
var arr = [1, 2, [3, 4]];
// 展开一层数组
arr.flat();
// 等效于
arr.reduce((acc, val) => acc.concat(val), []);
// [1, 2, 3, 4]
// 使用扩展运算符 ...
const flattened = arr => [].concat(...arr);
flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 连着深度值为1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。给个例子。
let 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"]
14、forEach
forEach() 方法对数组的每个元素执行一次给定的函数。
语法
arr.forEach(callback(currentValue [, index [, array]])[, thisArg])
- forEach() 本身不会改变原数组,但是callback函数可能会改变里面的值。
- 已删除的项不会被遍历到,如果已访问的元素在迭代时被删除了(例如使用shift),之后的元素将被跳过。
- 不对未初始化的值进行任何操作(稀疏数组)
注意: 除了抛出异常以外,没有办法中止或跳出 forEach() 循环。如果你需要中止或跳出循环,forEach() 方法不是应当使用的工具。
打印出数组的内容,或者可以使用console.table展示
function logArrayElements(element, index, array) {
console.log('a[' + index + '] = ' + element);
}
shift后会跳过three。
var words = ['one', 'two', 'three', 'four'];
words.forEach(function(word) {
console.log(word);
if (word === 'two') {
words.shift();
}
});
// one
// two
// four
15、includes是否包含值
includes() 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回 false。(那我直接使用indexOf不就行了?)
arr.includes(valueToFind[, fromIndex])
16、keys和values
keys() 方法返回一个包含数组中每个索引键的Array Iterator对象。
遍历,并且还有这个新东西。
var arr = ["a", , "c"];
var sparseKeys = Object.keys(arr);
var denseKeys = [...arr.keys()];
console.log(sparseKeys); // ['0', '2']
console.log(denseKeys); // [0, 1, 2]
两个都扎不多
let arr = ['w', 'y', 'k', 'o', 'p'];
let eArr = arr.values();
for (let letter of eArr) {
console.log(letter);
} //"w" "y "k" "o" "p"
17、map
map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。(一定要返回新数组,要不然没用的,不会对原数组进行修改的,请使用forEach或者for…of)
map 不修改调用它的原数组本身(当然可以在 callback 执行时改变原数组)
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
一般的map方法,下面的例子演示如何在一个String上使用 map 方法获取字符串中每个字符所对应的 ASCII 码组成的数
var map = Array.prototype.map
var a = map.call("Hello World", function(x) {
return x.charCodeAt(0);
})
// a的值为[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
18、reduce
reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
accumulator
累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。
currentValue
数组中正在处理的元素。
index 可选
数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始。
array可选
调用reduce()的数组
initialValue可选
作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。
**注意:**如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
回调函数第一次执行时,
accumulator和currentValue的取值有两种情况:如果调用reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;如果没有提供initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。
var maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x );
var maxCallback2 = ( max, cur ) => Math.max( max, cur );
// reduce() 没有初始值
[ { x: 2 }, { x: 22 }, { x: 42 } ].reduce( maxCallback ); // NaN 这里为什么为NaN?因为accumulator只有第一次初始化之后就没用到了,那么之后就会undefined了,需要return,把值返回给accumulator,那么之后才会有值。
[ { x: 2 }, { x: 22 } ].reduce( maxCallback ); // 22
[ { x: 2 } ].reduce( maxCallback ); // { x: 2 }
[ ].reduce( maxCallback ); // TypeError
// map/reduce; 这是更好的方案,即使传入空数组或更大数组也可正常执行
[ { x: 22 }, { x: 42 } ].map( el => el.x )
.reduce( maxCallback2, -Infinity );
具体运行过程可以看这张表
[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array){
return accumulator + currentValue;
});
callback |
accumulator |
currentValue |
currentIndex |
array |
return value |
|---|---|---|---|---|---|
| first call | 0 |
1 |
1 |
[0, 1, 2, 3, 4] |
1 |
| second call | 1 |
2 |
2 |
[0, 1, 2, 3, 4] |
3 |
| third call | 3 |
3 |
3 |
[0, 1, 2, 3, 4] |
6 |
| fourth call | 6 |
4 |
4 |
[0, 1, 2, 3, 4] |
10 |
其实用prev和curr更好理解,每次需要返回值给prev。而且prev没有初始化的话,是取索引0的值,这样子就好理解了。
数组里面所有值的和,建议给个初始值。
[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr,0 );
累加对象数组里的值
var initialValue = 0;
var sum = [{x: 1}, {x:2}, {x:3}].reduce(function (accumulator, currentValue) {
return accumulator + currentValue.x;
},initialValue)
console.log(sum) // logs 6
二维转一维
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
function(a, b) {
return a.concat(b);
},
[]
);
还有一些例子,很值得看https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
reduceRight() 方法接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。
19、reverse反转
reverse() 方法将数组中元素的位置颠倒,并返回该数组。数组的第一个元素会变成最后一个,数组的最后一个元素变成第一个。该方法会改变原数组。
20、排序sort
**sort()** 方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的。
返回排序后的数组。请注意,数组已原地排序,并且不进行复制。
要比较数字而非字符串,比较函数可以简单的以 a 减 b,如下的函数将会将数组升序排列
numbers.sort((a, b) => a - b);
21、splice
splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
deleteCount 可选
如果 deleteCount 被省略了,或者它的值大于等于array.length - start(也就是说,如果它大于或者等于start之后的所有元素的数量),那么start之后数组的所有元素都会被删除。
如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。
返回由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。
22、迭代器
语法
arr[Symbol.iterator]()
数组的 iterator 方法,默认情况下,与values 返回值相同, arr[Symbol.iterator] 则会返回values 函数。
实例属性
1、length
下标超出了当前数组的大小,会进行修改length这个值。
const fruits = []
fruits.push('banana', 'apple', 'peach')
fruits[5] = 'mango'
console.log(fruits[5]) // 'mango'
console.log(Object.keys(fruits)) // ['0', '1', '2', '5']
console.log(fruits.length) // 6
也可以显式的给length赋值一个更大的值
fruits.length = 10
console.log(fruits) // ['banana', 'apple', 'peach', empty x 2, 'mango', empty x 4]
console.log(Object.keys(fruits)) // ['0', '1', '2', '5']
console.log(fruits.length) // 10
console.log(fruits[8]) // undefined
或者可以截断这个数组
var numbers = [1, 2, 3, 4, 5];
if (numbers.length > 3) {
numbers.length = 3;
}
console.log(numbers); // [1, 2, 3]
console.log(numbers.length); // 3
一些操作
1、数组去重合并
function combine(){
let arr = [].concat.apply([], arguments); //没有去重复的新数组
return Array.from(new Set(arr));
}
var m = [1, 2, 2], n = [2,3,3];
console.log(combine(m,n)); // [1, 2, 3]
或者使用reduce和indexof
let myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd']
let myOrderedArray = myArray.reduce(function (accumulator, currentValue) {
if (accumulator.indexOf(currentValue) === -1) {
accumulator.push(currentValue)
}
return accumulator
}, [])
或者reduce加上排序
let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4];
let result = arr.sort().reduce((init, current) => {
if(init.length === 0 || init[init.length-1] !== current) {
init.push(current);
}
return init;
}, []);
console.log(result); //[1,2,3,4,5]
2、创建数组
二维数组,切记不能使用这种方式,我就说怎么没有人呢,这种方式会只创建一个二维数组,然后里面每个都是相同的引用,非常的蛋疼。
new Array(n).fill(new Array(n).fill(0));
二维数组创建得用map
new Array(n).fill(0).map(() => new Array(n).fill(0));





