0%

JavaScript数组操作

创建一个数组:

1
let fruits = ['apple', 'banana'];

已知斐波那契数列中第一个数字是1,第二个数字是2,从第三项开始,每一项都等于前两项之和。求斐波那契数列的前20个数字:

1
2
3
4
5
6
7
8
var fibonacci = [0];
fibonacci[1] = 1;
fibonacci[2] = 2;

for (var i = 3; i < 20; i ++) {
fibonacci[i] = fibonacci[i - 1] + fibonacci[i - 2];
}
console.log(fibonacci);

添加和删除元素

在JavaScript中,数组是一个可以动态修改的对象,如果添加元素,它就动态增长。

push方法

push方法将元素添加到数组的末尾。可以一次添加多个

1
2
3
var arr = [0];
arr.push(3);
arr.push(1,2,3,4);//(5) [0, 1, 2, 3, 4]

pop方法

pop方法删除数组的最后一个元素

1
arr.pop();//(6) [-1, -2, 0, 1, 2, 3]

unshift方法

unshift方法直接把元素插入到数组首位

1
arr.unshift(-1, -2);//(5) [0, 1, 2, 3, 4]

shift方法

shift方法删除数组的第一个元素

1
arr.shift();//(5) [-2, 0, 1, 2, 3]

splice方法

splice可以在数组特定位置处删除或增加一定数量的元素。
参数:

  • start 指定修改的开始位置,从0计数,如果超出了数组的长度,则从数据末尾开始添加内容,如果是负值,则表示从数组末的第几位开始(从1计数)
  • deleteContent (可选)表示需要移除的数组元素的个数,如果是0表示不移除元素,这种情况下,至少应添加一个新元素。如果deleteCount大于start之后的元素的总数,则表示从start后面的 元素都将被删除(含第start位),如果deleteCount被省略,则相当于(arr.length - start)
  • item1, item2,…(可选)从start位置开始,如果不指定,则splice将只删除数组元素。
  • 返回值 由被删除的元素组成一个新的数组,如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除,则返回空数组。
1
2
3
4
5
6
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.splice(2);// (2) [0, 1] 将第3个也删除了
arr.splice(-2);// (8) [0, 1, 2, 3, 4, 5, 6, 7] 从1计数,将第-2个也删除了
arr.splice(2, 3);//(7) [0, 1, 5, 6, 7, 8, 9]
arr.splice(2, 3, 12, 13, 14);//(10) [0, 1, 12, 13, 14, 5, 6, 7, 8, 9] 从第3个开始,删除3个元素,然后将(12, 13, 14)这三个元素加入到第3个元素处
arr.splice(2, 0, 12, 13, 14);//(13) [0, 1, 12, 13, 14, 2, 3, 4, 5, 6, 7, 8, 9] 从第3个元素开始,不删除元素,新增(12, 13, 14)这三个元素

数组操作

填充数组 fill()

Array.prototype.fill()方法使用一个固定值填充一个数组中从起始索引到结束索引的全部元素,不包括结束索引。

1
2
const arr = [1, 2, 3, 4];
arr.fill(0, 2, 3); // 将值1填充从索引2开始,索引3结束: [1, 2, 0, 4]

语法:arr.fill(value[, start[, end]]),参数说明:

  • value 必须,用来填充数组元素的值。
  • start 可选,起始索引,默认值为0。如果start为负值,则开始索引会被自动计算为length + start,其中lengththis对象的length属性。
  • end 可选,结束索引,默认值为数组长度。如果end为负值,则结束索引会被自动计算为length + end

fill方法是一个通用方法,改方法不要求this是数组对象。fill方法会改变调用它的this对象本身,然后返回它。

当一个对象被传递给fill方法时,填充数组的是这个对象的引用。

例如,下面这个例子通过Function.prototype.call()方法改变了调用fillthis

1
[].fill.call({length: 3}, 4); 

call[].fill()方法的this修改为了一个对象{length: 3},然后传递了value值为4。所以这里fill()方法会读取this对象即{length: 3}的length属性,然后从0length依次赋值。得出的结果为:

1
{ '0': 4, '1': 4, '2': 4, length: 3 }

当然,如果这个this对象没有length属性的话,那么这个fill()方法也不会起作用。

数组合并 concat()

concat方法用于合并两个或多个数组。concat方法并不修改调用它的对象和参数中的各个数组本身的值,而是将他们的每个元素拷贝一份放在组合成的新数组中。原数组中的元素有两种拷贝方式:

  • 对象引用(非对象直接量)concat方法会复制对象引用放到组合的新数组里,原数组和新数组都指向同一个实际的对象,所以,当实际的对象被修改时,两个数组同时也会被修改。
  • 字符串和数字(是原始值,而不是包装原始值的String和Number对象)concat方法会复制字符串和数字的值放到新的数组里面。
1
2
3
4
5
var num1 = [1, 2, 3];
var num2 = [4, 5, 6];
var num3 = [7, 8, 9];
// 组成新数组[1, 2, 3, 4, 5, 6, 7, 8, 9]; 原数组 num1, num2, num3 未被修改
var nums = num1.concat(num2, num3);

对象引用,修改合并的数组,原对象也发生了变化:

1
2
3
4
5
6
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var obj = {a: 3};
var newArr = arr.concat(obj);
newArr[10].b = 3;
console.log(newArr);//(14) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, Object, "a", "b", "c"]
console.log(obj);//Object {a: 3, b: 3}

数组切片 slice()

Array.prototype.slice方法返回一个新的数组对象,这个对象是由beginend决定的原数组的浅拷贝(包括begin,不包括end)。原始数组不会发生改变。

1
2
3
4
5
const arr = [1, 2, 3, 4, 5];
// 区间
const a = arr.slice(2, 3); // [3]
// 全省略
const b = arr.slice(); // [1, 2, 3, 4, 5]

参数描述:

  • begin 可选,提取开始处的索引(从0开始)。如果该参数为负数,则表示从原数组中的倒数几个元素开始提取。比如:slice(-2)表示提取从倒数第二个开始到最后一个元素。如果省略,则表示切片的索引从0开始。如果begin大于原数组的长度,则返回空数组。如果负数的绝对值小于数组的长度,那么等效于0.
  • end 可选,提取终止除的索引(从0开始)。在该索引处结束提取原数组,提取出的数组不包含end处的索引。如果参数为负数,表示在原数组中的倒数第几个元素结束抽取。如果end被省略,则slice会一直提取到数组的末尾,如果end大于数组的长度,也会一直提取到原数组的末尾。

slice对元素组切片,但是不会修改原数组,只会返回一个浅复制了原数组中元素的一个新数组。拷贝规则:

  • 如果该元素是个对象引用(不是实际对象),slice会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生了改变,那么新的数组和原来的数组中的这个元素都会发生改变。
  • 对于字符串、数字以及布尔值来说(不是StringNumberBoolean对象),slice都会拷贝这些值到新的数组里。在别的数组里修改这些值,将不会印象另一个数组。

如果向原数组或新数组中添加了新元素,另一个不会受影响。

迭代器函数

every 方法

every方法测试数组的所有元素是否都通过了指定函数的测试。every方法为数组中的每个元素执行一次callback函数,直到它找到一个使callback返回false的元素。every遍历的元素范围在第一次调用callback的时候就已经确定了,在调用every之后添加到数组中的元素不会被callback访问到。
参数:

  • currentValue 当前值
  • index 索引
  • array 正在操作的数组
1
2
3
4
5
6
7
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var result = arr.every(function(element, index, array){
array[index] = index - 1;
return element < 5;
});
console.log('result: ', result);//false
console.log('arr: ', arr);//arr: (10) [-1, 0, 1, 2, 3, 4, 6, 7, 8, 9]

在every内部改变原数组,迭代不受影响,在第一次返回false的时候终止。

every方法的好玩之处是相当于且表达式,比如,要检测多个字符串里面是否全包含一个字符:

1
2
3
4
let str = 'a', reuslt = null; 
if ('ab'.indexOf(str) !== -1 && 'ac'.indexOf(str) !== -1 && 'ac'.indexOf(str) !== -1) {
result = true;
}

可以用every改造为:

1
2
3
4
5
6
const arr = ['ab', 'ac', 'a5'];
function includeStr(str) {
return arr.every(item => item.indexOf(str) !== -1);
}
console.log(includeStr('a')); // 输出:true,都包含'a'
console.log(includeStr('b')); // 输出:false,有些不包含

注意:如果在迭代时删除数组元素,之后的元素会被跳过。

some 方法

some方法用于检测数组中的元素是否满足指定条件(函数提供),该方法会依次执行数组中的每一个元素,如果有一个元素满足条件,则表达式返回true,剩余的元素不再遍历;如果没有满足条件的元素,则返回false。

这个函数适用于或的表达式,比如,检测数组中是否包含某个字符:

1
2
3
4
let str = 'a', reuslt = null; 
if ('ab'.indexOf(str) !== -1 || 'ac'.indexOf(str) !== -1 || 'ac'.indexOf(str) !== -1) {
result = true;
}

判断起来很繁琐,可以使用some函数改造为:

1
2
3
4
5
6
7
const arr = ['ab', 'ac', 'a5'];
function includeStr(str) {
return arr.some(item => item.indexOf(str) !== -1);
}
console.log(includeStr('a')); // 输出:true,都包含
console.log(includeStr('c')); // 输出:true,部分包含
console.log(includeStr('z')); // 没有包含

forEach方法

forEach方法为数组的每一项执行一次callback的函数,遍历的范围也是在第一次调用callback的时候确定,不再改变。参数同上。
注意:如果在迭代时删除数组元素,之后的元素会被跳过。

map方法

map方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
参数:

  • currentValue 当前值
  • index 索引
  • array 正在操作的数组
1
2
3
4
5
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var newArr = arr.map(function(element, index){
return element + 2;
});
console.log(newArr);//(10) [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

filter方法

filter方法创建一个新数组,其包含通过其所提供函数实现测试的所有元素。
filter为数组中的每个元素调用一次callback,并利用所有使callback返回true或等价于true的元素创建一个新数组,

1
2
3
4
5
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var newArr = arr.filter(function(element, index){
return element % 2 == 0;
});
console.log(newArr);//(5) [0, 2, 4, 6, 8]

reduce方法

reduce方法对累加器和数组中的每个元素(从左到右)应用一个函数,将其减少为单个值。
语法为:

1
array.reduce(function(accumulator, currentValue, currentIndex, array), initialValue)

参数:

  • accumulator 上一次调用回调返回的值,或是提供的初始值initialValue
  • currentValue 数组正在处理的元素
  • currentIndex 数据正在处理的元素的索引
  • initialValue 可选项,用于第一次调用callback的一个参数,如果没有设置初始值,则将数组中的第一个元素作为初始值。空数组调用reduce时没有设置初始值会报错。

例如:

1
2
3
4
5
const arr = [1, 2, 3, 4];
const total = arr.reduce((sum, i) => {
return sum + i;
});
console.log(total); // 控制台输出:15

PS:特别注意在当数组项是对象的时候做累加的时候,一定要传递初始值,否则会直接用第一个对象来做累加操作,会出现[Object Object]的错误东西。

find和findIndex方法(ES6)

find方法为es6新增方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员,如果没有符合的成员,就返回undefined。例如,找出第一个小于0的成员:

1
[1, 4, -5, 10].find((n) => n < 0) // -5

find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组:

1
2
3
4
[1, 4, -5, 10].find((value, index, arr) => {
return value > 9;
});
// 10

findIndex方法和find方法类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1.

1
2
3
4
[1, 4, -5, 10].find((value, index, arr) => {
return value > 9;
});
// 3

这两个方法都可以接受第二个参数,用来绑定回调函数的this对象:

1
2
3
4
5
6
let person = {name: 'tony', age: 3};
function f(v) {
return v > this.age;
}
[1, 4, -5, 10].find(f, person);
// 4;

也可以写为:

1
2
3
4
[1, 4, -5, 10].find(function(value){
return v > this.age;
}, {name: 'tony', age: 3});
// 4

数组排序

sort方法

sort方法在适当的位置对数组的元素进行排序,并返回数组。sort排序不一定是稳定的,默认排序顺序是根据字符串unicode码点。返回排序后的数组,原数组已经被排序后的数组替代。
如果没有指明排序的函数,那么元素会按照转换为字符串的字符unicode进行排序。如果指明了排序函数,就按照排序结果的返回值进行排序,函数形式为compareFun(a, b)。a和b是两个将要被比较的元素。
根据函数compareFun(a, b)的结果进行排序:

  • 结果小于0,那么a会排到b之前
  • 结果等于0,那么a和b的相对位置不变
  • 结果大于0, b会排到a之前
1
2
3
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 16, 14];
arr.sort(function(a, b){ return a - b;});
console.log(arr);//(15) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16]
码字辛苦,打赏个咖啡☕️可好?💘