总结javaScript语言Array对象上的api

465 阅读13分钟

序言

javaScript的数组对象是我们在实际开发中经常用到的,so以此总结来增加印象,顺便提了几个容易误区的点。

一、常用方法一(改变自身)

1.Array.pop()

pop() 方法删除一个数组中的最后的一个元素,并且返回这个元素,改变原来数组,后进先出的出栈过程

var arr = [1, 2, 3, 4, 5]  
arr.pop() 
console.log(arr) // 1,2,3,4

2.Array.push()

方法添加一个或者多个元素到数组末尾,并且返回数组新的长度,改变原来数组。入栈的过程

var arr = [1, 2, 3, 4, 5]  
arr.push(6, 7)  
console.log(arr) // 1,2,3,4,5,6,7

3.Array.unshift()

方法用于在数组开始处插入一些元素(就像是栈底插入),并返回数组新的长度。

var arr = [1, 2, 3, 4, 5]  
arr.unshift(6, 7)  
console.log(arr) // 6,7,1,2,3,4,5

4.Array.shift()

shift()方法删除数组的第一个元素,并返回这个元素。出栈过程

var arr = [1, 2, 3, 4, 5]  
arr.shift() 
console.log(arr) // 2,3,4,5

5.Array.splice()

splice()方法用新元素替换旧元素的方式来修改数组。它是一个常用的方法,复杂的数组操作场景通常都会有它的身影,特别是需要维持原数组引用时,就地删除或者新增元素,splice是最适合的。

arr.splice(start,deleteCount[, item1[, item2[, …]]])

start 指定从哪一位开始修改内容。如果超过了数组长度,则从数组末尾开始添加内容;如果是负值,则其指定的索引位置等同于 length+start (length为数组的长度),表示从数组末尾开始的第 -start 位

deleteCount 指定要删除的元素个数,若等于0,则不删除。这种情况下,至少应该添加一位新元素,若大于start之后的元素总和,则start及之后的元素都将被删除。

itemN 指定新增的元素,如果缺省,则该方法只删除数组元素。

返回值 由原数组中被删除元素组成的数组,如果没有删除,则返回一个空数组。

var arr = ["a","b","c"];
var splices = arr.splice(1,1);
console.log(arr); // ["b","c"]
console.log(splices); // ["a"] 可见是从数组下标为1的元素开始删除,并且删除一个元素,由于itemN缺省,故此时该方法只删除元素

var arr = ["a","b"];
var splices = arr.splice(2,1,"d");
console.log(arr); // ["a", "b", "d"]
console.log(splices); // [], 可见由于start超过数组长度,此时从数组末尾开始添加元素,并且原数组不会发生删除行为

var array = ["apple","boy"];
var splices = array.splice(-2,1,"cat");
console.log(array); // ["cat", "boy"]
console.log(splices); // ["apple"], 可见当start为负值时,是从数组末尾开始的第-start位开始删除,删除一个元素,并且从此处插入了一个元素

var array = ["apple","boy"];
splices = array.splice(-3,1,"cat");
console.log(array); // ["cat", "boy"]
console.log(splices); // ["apple"], 可见即使-start超出数组长度,数组默认从首位开始删除

var array = ["apple","boy"];
splices = array.splice(0,3,"cat");
console.log(array); // ["cat"]
console.log(splices); // ["apple", "boy"], 可见当deleteCount大于数组start之后的元素总和时,start及之后的元素都将被删除

6.Array.reverse()

reverse()方法颠倒数组中元素的位置,第一个会成为最后一个,最后一个会成为第一个,该方法返回对数组的引用。

var array = [1,2,3,4,5];
var array2 = array.reverse();
console.log(array); // [5,4,3,2,1]
console.log(array2===array); // true

7.Array.sort()

sort()方法对数组元素进行排序,并返回这个数组。sort方法比较复杂,这里我将多花些篇幅来讲这块。

var array = ["1","3","4","2"];
var array2 = array.sort(function(a,b){
    return a > b
});
console.log(array);
console.log(array2 == array); // true

//如果缺省,数组元素将按照各自转换为字符串的Unicode(万国码)位点顺序排序
array = [10, 1, 3, 20];
var array3 = array.sort();
console.log(array3); // [1, 10, 20, 3]

补充小知识--类数组对象转换数组,即 鸭式变形

var o = {0:"cat", 1:"dog", 2:"cow", 3:"chicken", 4:"mouse", length:5}
var item = Array.prototype.pop.call(o); // 重点
console.log(o); // Object {0: "cat", 1: "dog", 2: "cow", 3: "chicken", length: 4}
console.log(item); // mouse

二、常用方法二(不改变自身)

1.Array.concat()

concat() 方法将传入的数组或者元素与原数组合并,组成一个新的数组并返回。

var array = [1, 2, 3];
var array2 = array.concat(4,[5,6],[7,8,9]);
console.log(array2); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(array); // [1, 2, 3], 可见原数组并未被修改

// 若concat方法中不传入参数,那么将基于原数组浅复制生成一个一模一样的新数组(指向新的地址空间)
var array = [{a: 1}];
var array3 = array.concat();
console.log(array3); // [{a: 1}]
console.log(array3 === array); // false
console.log(array[0] === array3[0]); // true,新旧数组第一个元素依旧共用一个同一个对象的引用

补充小点

push()方法与concat() 的时间复杂度谁的高?

push()函数是会修改原有的数组数据,执行push()方法后原有数组的值会对应的改变;而concat()方法则是先把原数组原封不动的复制到一个新的数组,然后在新数组上进行操作,所以concat()不会改变原数组的值。

2.Array.join()

join() 方法将数组中的所有元素连接成一个字符串。

arr.join([separator = ‘,’])separator可选,缺省默认为逗号。

var array = ['We', 'are', 'Chinese'];
console.log(array.join()); // "We,are,Chinese"
console.log(array.join('+')); // "We+are+Chinese"
console.log(array.join('')); // "WeareChinese"

3.Array.slice()

slice() 方法将数组中一部分元素浅复制存入新的数组对象,并且返回这个数组对象。

arr.slice([start[, end]])

参数 start 指定复制开始位置的索引,end如果有值则表示复制结束位置的索引(不包括此位置)。

如果 start 的值为负数,假如数组长度为 length,则表示从 length+start 的位置开始复制,此时参数 end 如果有值,只能是比 start 大的负数,否则将返回空数组。

var array = ["one", "two", "three","four", "five"];
console.log(array.slice()); // ["one", "two", "three","four", "five"]
console.log(array.slice(2,3)); // ["three"]

4.Array.toString()

toString() 方法返回数组的字符串形式,该字符串由数组中的每个元素的 toString() 返回值经调用 join() 方法连接(由逗号隔开)组成。

语法:arr.toString()

var array = ['Jan', 'Feb', 'Mar', 'Apr'];
var str = array.toString();
console.log(str); // Jan,Feb,Mar,Apr

5.Array.indexOf()

indexOf() 方法用于查找元素在数组中第一次出现时的索引,如果没有,则返回-1

语法:arr.indexOf(element, fromIndex=0)

element 为需要查找的元素。

fromIndex 为开始查找的位置,缺省默认为0。如果超出数组长度,则返回-1。如果为负值,假设数组长度为length,则从数组的第 length + fromIndex项开始往数组末尾查找,如果length + fromIndex<0 则整个数组都会被查找。

indexOf使用严格相等(即使用 === 去匹配数组中的元素)。

var array = ['abc', 'def', 'ghi','123'];
console.log(array.indexOf('def')); // 1
console.log(array.indexOf('def',-1)); // -1 此时表示从最后一个元素往后查找,因此查找失败返回-1
console.log(array.indexOf('def',-4)); // 1 由于4大于数组长度,此时将查找整个数组,因此返回1
console.log(array.indexOf(123)); // -1, 由于是严格匹配,因此并不会匹配到字符串'123'

6.Array.lastIndexOf()

lastIndexOf() 方法用于查找元素在数组中最后一次出现时的索引,如果没有,则返回-1。并且它是indexOf的逆向查找,即从数组最后一个往前查找。

语法:arr.lastIndexOf(element, fromIndex=length-1)

element 为需要查找的元素。

fromIndex 为开始查找的位置,缺省默认为数组长度length-1。如果超出数组长度,由于是逆向查找,则查找整个数组。如果为负值,则从数组的第 length + fromIndex项开始往数组开头查找,如果length + fromIndex<0 则数组不会被查找。

同 indexOf 一样,lastIndexOf 也是严格匹配数组元素。

7.includes(ES7新增)

includes() 方法基于ECMAScript 2016(ES7)规范,它用来判断当前数组是否包含某个指定的值,如果是,则返回 true,否则返回 false。

语法:arr.includes(element, fromIndex=0)

element 为需要查找的元素。

fromIndex 表示从该索引位置开始查找 element,缺省为0,它是正向查找,即从索引处往数组末尾查找。

var array = [-0, 1, 2];
console.log(array.includes(+0)); // true
console.log(array.includes(1)); // true
console.log(array.includes(2,-4)); // true

以上,includes似乎忽略了 -0+0 的区别,这不是问题,因为JavaScript一直以来都是不区分 -0+0 的。

补充小点indexOf()和 includes()的区别

曾经一次面试,面试官给我写了一段下面,问我这段代码会有什么问题,问的我一脸懵逼,经常这么用没什么问题啊,后来他提示我 数字有一种类型是不等于自己的 ,这我才明白过来,是NaN, 如果下面代码 arr 数组里面有NaN的话,那这行代码就不准确了。所以es7出了个includes() 的api。

if(arr.indexOf(x)>-1) {}

这就是他们最直观的区别,includes能够发现NaN,而indexOf不能。

var array = [1,2,NaN];
console.log(array.includes(NaN)); // true
console.log(arra.indexOf(NaN)>-1); // false

三、常用方法三(遍历)

1. Array.forEach()

forEach() 方法指定数组的每项元素都执行一次传入的函数,返回值为undefined。

语法:arr.forEach(fn, thisArg)

fn 表示在数组每一项上执行的函数,接受三个参数:

  • value 当前正在被处理的元素的值
  • index 当前元素的数组索引
  • array 数组本身

thisArg 可选,用来当做fn函数内的this对象。

forEach 将为数组中每一项执行一次 fn 函数,那些已删除,新增或者从未赋值的项将被跳(但不包括值为 undefined 的项)。

var array = [1, 3, 5];
var obj = {name:'cc'};
var sReturn = array.forEach(function(value, index, array){
  array[index] = value * value;
  console.log(this.name); // cc被打印了三次
},obj);
console.log(array); // [1, 9, 25], 可见原数组改变了
console.log(sReturn); // undefined, 可见返回值为undefined

2.Array.map()

map() 方法遍历数组,使用传入函数处理每个元素,并返回函数的返回值组成的新数组。

语法:arr.map(fn, thisArg)

参数介绍同 forEach 方法的参数介绍。

补充小点forEach() 和 map()的区别

forEach没有返回值,可以改变原来数组。

map()会返回一个新的数组,但不会改变原来数组

3.Array.filter()

filter() 方法使用传入的函数测试所有元素,并返回所有通过测试的元素组成的新数组。它就好比一个过滤器,筛掉不符合条件的元素。

语法:arr.filter(fn, thisArg)

var array = [18, 9, 10, 35, 80];
var array2 = array.filter(function(value, index, array){
  return value > 20;
});
console.log(array2); // [35, 80]

4.Array.reduce()  Array.reduceRight() 

reduce() 方法接收一个方法作为累加器,数组中的每个值(从左至右) 开始合并,最终为一个值。

reduceRight() 方法接收一个方法作为累加器,数组中的每个值(从右至左)开始合并,最终为一个值。除了与reduce执行方向相反外,其他完全与其一致,请参考上述 reduce 方法介绍。

语法:arr.reduce(fn, initialValue)

fn 表示在数组每一项上执行的函数,接受四个参数:

  • previousValue 上一次调用回调返回的值,或者是提供的初始值
  • value 数组中当前被处理元素的值
  • index 当前元素在数组中的索引
  • array 数组自身

initialValue 指定第一次调用 fn 的第一个参数。

当 fn 第一次执行时:

  • 如果 initialValue 在调用 reduce 时被提供,那么第一个 previousValue 将等于 initialValue,此时 item 等于数组中的第一个值;
  • 如果 initialValue 未被提供,那么 previousVaule 等于数组中的第一个值,item 等于数组中的第二个值。此时如果数组为空,那么将抛出 TypeError。
  • 如果数组仅有一个元素,并且没有提供 initialValue,或提供了 initialValue 但数组为空,那么fn不会被执行,数组的唯一值将被返回。

var array = [1, 2, 3, 4];
var s = array.reduce(function(previousValue, value, index, array){
  return previousValue * value;
},1);
console.log(s); // 24
// ES6写法更加简洁
array.reduce((p, v) => p * v); // 24
callbackpreviousValuecurrentValueindexarrayreturn value
第1次110[1,2,3,4]1
第2次121[1,2,3,4]2
第3次232[1,2,3,4]6
第4次643[1,2,3,4]24

5.Array.every()

every() 方法使用传入的函数测试所有元素,只要其中有一个函数返回值为 false,那么该方法的结果为 false;如果全部返回 true,那么该方法的结果才为 true。

var arr = [10,8,20,15,16]
var bool = arr.every(function(value, index, obj){
  return value >= 8;
});
console.log(bool); // true

6.Array.some()

some() 方法刚好同 every() 方法相反,some 测试数组元素时,只要有一个函数返回值为 true,则该方法返回 true,若全部返回 false,则该方法返回 false。

var arr = [10,8,20,15,16]
var bool = arr.every(function(value, index, obj){
  return value > 15;
});
console.log(bool); // true

7.Array.find() Array.findIndex()

find() 方法基于ECMAScript 2015(ES6)规范,返回数组中第一个满足条件的元素(如果有的话), 如果没有,则返回undefined。

findIndex() 方法也基于ECMAScript 2015(ES6)规范,它返回数组中第一个满足条件的元素的索引(如果有的话)否则返回-1。

语法:arr.find(fn, thisArg)

arr.findIndex(fn, thisArg)

我们发现它们的语法与forEach等十分相似,其实不光语法,find(或findIndex)在参数及其使用注意事项上,均与forEach一致。因此此处将略去 find(或findIndex)的参数介绍。下面我们来看个例子

var array = [1, 3, 5, 7, 8, 9, 10];
function f(value, index, array){
  return value%2==0; // 返回偶数
}
function f2(value, index, array){
  return value > 20; // 返回大于20的数
}
console.log(array.find(f)); // 8
console.log(array.find(f2)); // undefined
console.log(array.findIndex(f)); // 4
console.log(array.findIndex(f2)); // -1

8.Array.entries()

9.Array.keys()

10.Array.values()

四、ES6新增的构造函数方法

1.Array.from()

用于把两类对象转化成真的数组:

a.类似数组的的对象(就是任何有length属性的对象);

b.可遍历的对象;

let arrayLike = {
    '0': 'a',
    '1': 'b',
    '2': 'c',
    length: 3
};

// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']

// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

第二个参数 有map 的功能

Array.from(arrayLike, x => {x * x })
//等同于
Array.from(arrayLike).map(x => x * x);

第三个参数可以绑定 this

如果map函数里面用到了this关键字,还可以传入Array.from的第三个参数,用来绑定this

var y = 1
Array.from(arrayLike, x => {x * y }, window)

2. Array.of()

方法用于将一组值转化为数组

Array.of(1,2,3,4)  //[1,2,3,4]
Array.of(3) // [3]
Array.of(3).length // 1

这个方法的主要目的,是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。

Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]

Array.of基本上可以用来替代Array()new Array(),并且不存在由于参数不同而导致的重载。它的行为非常统一。

Array.of() // []
Array.of(undefined) // [undefined]
Array.of(1) // [1]
Array.of(1, 2) // [1, 2]

Array.of总是返回参数值组成的数组。如果没有参数,就返回一个空数组。

Array.of方法可以用下面的代码模拟实现。

function ArrayOf(){
  return [].slice.call(arguments);
}

3.Array.find()

用于查找第一个符合条件的数组成员。直到找出第一个返回值为true的成员,然后返回改成员。如果没有返回条件的成员,则返回undefined

4.Array.findIndex()

与find方法相同,找不到放回-1

[NaN].findIndex(y => Object.is(NaN, y))

5.Array.fill()

fill方法使用给定的值,填充一个数组

['a', 'b', 'c'].fill(7)
// [7, 7, 7]

new Array(3).fill(7)
// [7, 7, 7]

fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。

['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']

五、判断方法

Array.isArray([])

判断是都是数组,不多讲了