Javascript -- 精通Array

240 阅读12分钟

属性呢,就是可以直接访问的变量,对于Array来说,只有length;方法,就是一些api。

Notes:

  • Array.from('123') ---- ['1','2','3']

  • Array.ofnew Array()的区别在于对于一个参数

      Array.of(3)    // [3]
      new Array(3)   // [empty * 3]
    
  • [...arguments]这样会得到一个数组,其中arguments是一个类数组对象,用法和Array.from一样,也可以传个字符串

  • Array.prototype.valueOf方法返回一个数组,Array.prototype.toString方法返回一个字符串,比如[1,2,3].toString() // '1,2,3',所以隐式类型转换会调用toString方法

  • 使用for...of循环,遍历数组会得到值,使用for...in会得到key,比如0,1,2

遍历api

forEach : ie9+,用于调用数组的每个元素,并将元素传递给回调函数,那些已删除或者未初始化的项将被跳过(例如在稀疏数组上),也就是forEach会跳过empty项,注意并不会跳过undefined和null项。返回值undefined。没有办法中止或者跳出 forEach 循环,除了抛出一个异常。

稀疏数组就是包含从0开始的不连续索引的数组
以下a和c都为稀疏数组,虽然数组存在长度,但数组单元并不存在
var a = new Array(3); // 输出 empty * 3
var b = [undefined, undefined, undefined];
var c = []; c.length = 3;

数组元素值 * 2:

arr.forEach(function(val, index, arr) {
    arr[index]=val*2;
})

下面的例子输出"one", "two", "four"。当到达包含值"two"的项时,整个数组的第一个项被移除了,这导致所有剩下的项上移一个位置。因为元素 "four"现在在数组更前的位置,"three"会被跳过。

var words = ["one", "two", "three", "four"];
words.forEach(function(word) {
  console.log(word);
  if (word === "two") {
    words.shift();
  }
});
// one two four

map : ie9+,返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。注意: map() 不会对空数组进行检测,也不会改变原始数组。不写return的话,但是会处理稀疏数组中的empty项,会默认return undefined

Using map generically,比如在String上使用map

var map = Array.prototype.map;
var a = map.call('Hello World', function(x) { 
  return x.charCodeAt(0); 
});

一些有趣的运用技巧:
exp1:

var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt); // 1, 2, 3

exp2:

['1', '2', '3'].map(parseInt); // 1, NaN, NaN
// parseInt有两个参数,而map传递了3个参数,也就是把value、index传给parseInt了
// index 0: parseInt('1', 0)
// index 1: parseInt('2', 1)
// index 2: parseInt('3', 2)

exp3:

['1.1', '2.2e2', '3e300'].map(Number); 
// [1.1, 220, 3e+300]

reduce : 接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值,返回计算结果。

如果不传递initialValue,那么数组第一个值会被传递,也就是total=arr[0]
举个简单的应用🌰

var initialValue = 0;
var sum = [{x: 1}, {x:2}, {x:3}].reduce(
    (accumulator, currentValue) => accumulator + currentValue.x
    ,initialValue
);

console.log(sum) // logs 6

reduceRight : 功能和 reduce() 功能是一样的,不同的是 reduceRight() 从数组的末尾向前将数组中的数组项做累加,当不传initial value时,curVal会等于数组倒数第二项。空数据执行reduce,如果不传initial value,是会报错的。

键值对

keys : 方法返回一个包含数组中每个索引键的Array Iterator对象,迭代器有两个值,一个value、一个done,value是当前指向的值,done是迭代完成没有

var arr = ["a", , "c"];
var sparseKeys = Object.keys(arr);
var denseKeys = [...arr.keys()];
console.log(sparseKeys); // ['0', '2']
console.log(denseKeys);  // [0, 1, 2]
console.log(arr.keys().next().value); // 0

values : 方法返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值,也是IE不支持

let arr = ['w', 'y', 'k', 'o', 'p'];
let eArr = arr.values();
// 您的浏览器必须支持 for..of 循环
// 以及 let —— 将变量作用域限定在 for 循环中
for (let letter of eArr) {
  console.log(letter);
}

entries : 方法返回一个新的 Array Iterator 对象,该对象返回key/value的键值对,也是IE不支持

var array1 = ['a', 'b', 'c'];
var iterator1 = array1.entries();

console.log(iterator1.next().value);
// expected output: Array [0, "a"]
console.log(iterator1.next().value);
// expected output: Array [1, "b"]

数组元素操作

pop : 方法用于删除数组的最后一个元素并返回删除的元素,此方法更改数组的长度。该方法和 call() 或 apply() 一起使用时,可应用在类似数组的对象上。pop方法根据 length属性来确定最后一个元素的位置。如果不包含length属性或length属性不能被转成一个数值,会将length置为0,并返回undefined。如果你在一个空数组上调用 pop(),它返回 undefined。

push : 方法将一个或多个元素添加到数组的末尾,并返回新数组的长度,新元素将添加在数组的末尾。

array.push(item1, item2, ..., itemX)

shift : 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。此方法改变数组的长度!如果数组是空的,那么 shift() 方法将不进行任何操作,返回 undefined 值。请注意,该方法不创建新数组,而是直接修改原有的 arrayObject。

unshift : unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。unshift() 方法不创建新的创建,而是直接修改原有的数组。unshift() 方法无法在 Internet Explorer 中正确地工作!

concat : 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。它由被调用的对象中的元素组成,每个参数的顺序依次是该参数的元素(如果参数是数组)或参数本身(如果参数不是数组)。它不会递归到嵌套数组参数中。

var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])

注意:合并嵌套数组,会保留引用

var num1 = [[1]];
var num2 = [2, [3]];

var nums = num1.concat(num2);

console.log(nums);
// results in [[1], 2, [3]]

// modify the first element of num1
num1[0].push(4);

console.log(nums);
// results in [[1, 4], 2, [3]]

fill : 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。返回修改后的数组,会修改数组。 如果 start 是个负数, 则开始索引会被自动计算成为 length+start, 其中 length 是 this 对象的 length 属性值。如果 end 是个负数, 则结束索引会被自动计算成为 length+end

arr.fill(value[, start[, end]])

[].fill.call({ length: 3 }, 4);  // length: 3 表示数组数量

var arr = Array(3).fill({}) // [{}, {}, {}];
arr[0].hi = "hi"; // [{ hi: "hi" }, { hi: "hi" }, { hi: "hi" }]

// Objects by reference.
var arr = Array(3).fill({}) // [{}, {}, {}];
arr[0].hi = "hi"; // [{ hi: "hi" }, { hi: "hi" }, { hi: "hi" }]

filter : 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。filter() 不会对空数组进行检测。filter() 不会改变原始数组。

array.filter(function(currentValue,index,arr), thisValue) thisValue 默认为undefined

copyWithin : ie12+, 方法用于从数组的指定位置拷贝元素到数组的另一个指定位置中,而不修改其大小。返回值改变了的当前数组

array.copyWithin(target, start, end)

0 为基底的索引,开始复制元素的结束位置。copyWithin 将会拷贝到该位置,但不包括 end 这个位置的元素。如果是负数, end 将从末尾开始计算。

// ES2015 Typed Arrays are subclasses of Array
var i32a = new Int32Array([1, 2, 3, 4, 5]);

i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]

flat : 正在Draft阶段,很多浏览器不支持,比如IE。方法会递归到指定深度将所有子数组连接,并返回一个新数组。指定嵌套数组中的结构深度,默认值为1。

var newArray = arr.flat(depth)

var arr1 = [1, 2, [3, 4]];
arr1.flat(); 
// [1, 2, 3, 4]

flatMap : 正在Draft阶段,方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 和 深度值1的 flat 几乎相同,但flatMap通常在合并成一种方法的效率稍微高一些。

var new_array = arr.flatMap(function callback(currentValue[, index[, array]]) {
    // 返回新数组的元素
}[, thisArg])

// exp
var arr1 = [1, 2, 3, 4];

arr1.map(x => [x * 2]); 
// [[2], [4], [6], [8]]

// only one level is flattened
arr1.flatMap(x => [[x * 2]]);
// [[2], [4], [6], [8]]

join : 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果 arr.length 为0,则返回空字符串。

var elements = ['Fire', 'Wind', 'Rain'];

console.log(elements.join());
// expected output: Fire,Wind,Rain

console.log(elements.join(''));
// expected output: FireWindRain

slice : 方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象。且原始数组不会被修改。返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。支持负数,-1表示倒数第一个元素
arr.slice([begin[, end]])

splice : 方法通过删除现有元素和/或添加新元素来更改一个数组的内容。

array.splice(index,howmany,item1,.....,itemX)

sort :方法用原地算法对数组的元素进行排序,并返回数组。排序不一定是稳定的。默认排序顺序是根据字符串Unicode码点。
arr.sort([compareFunction])

reverse : 方法将数组中元素的位置颠倒。第一个数组元素成为最后一个数组元素,最后一个数组元素成为第一个。

toLocaleString : 返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 ",")隔开。
arr.toLocaleString([locales[,options]]);

元素查找

这类型是不会改变元数组的。 find : ie12+,方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。

在第一次调用 callback 函数时会确定元素的索引范围,因此在 find 方法开始执行之后添加到数组的新元素将不会被 callback 函数访问到。如果数组中一个尚未被callback函数访问到的元素的值被callback函数所改变,那么当callback函数访问到它时,它的值是将是根据它在数组中的索引所访问到的当前值。被删除的元素仍旧会被访问到。

findIndex : ie12+,方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。

与某些其他数组方法(如Array#some)不同,在稀疏数组中,即使对于数组中不存在的条目的索引也会调用回调函数。
在第一次调用callback函数时会确定元素的索引范围,因此在findIndex方法开始执行之后添加到数组的新元素将不会被callback函数访问到。如果数组中一个尚未被callback函数访问到的元素的值被callback函数所改变,那么当callback函数访问到它时,它的值是将是根据它在数组中的索引所访问到的当前值。被删除的元素仍然会被访问到。

some : ie9+,方法用于检测数组中的元素是否满足指定条件(函数提供)。

callback 只会在那些”有值“的索引上被调用,不会在那些被删除或从来未被赋值的索引上调用。如果为 some 提供了一个 thisArg 参数,将会把它传给被调用的 callback,作为 this 值。否则,在非严格模式下将会是全局对象,严格模式下是 undefined。

every : ie9+,方法用于检测数组所有元素是否都符合指定条件(通过函数提供)。

callback 只会为那些已经被赋值的索引调用。不会为那些被删除或从来没被赋值的索引调用。

every 遍历的元素范围在第一次调用 callback 之前就已确定了。在调用 every 之后添加到数组中的元素不会被 callback 访问到。如果数组中存在的元素被更改,则他们传入 callback 的值是 every 访问到他们那一刻的值。那些被删除的元素或从来未被赋值的元素将不会被访问到。

indexOf : 方法可返回数组中某个指定的元素位置。
arr.indexOf(searchElement[, fromIndex = 0])
开始查找的位置。如果该索引值大于或等于数组长度,意味着不会在数组里查找,返回-1。如果参数中提供的索引值是一个负值,则将其作为数组末尾的一个抵消,即-1表示从最后一个元素开始查找,-2表示从倒数第二个元素开始查找,以此类推。 注意:如果参数中提供的索引值是一个负值,并不改变其查找顺序,查找顺序仍然是从前向后查询数组。如果抵消后的索引值仍小于0,则整个数组都将会被查询。其默认值为0.

laseIndexOf : 方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从 fromIndex 处开始。
从此位置开始逆向查找。默认为数组的长度减 1,即整个数组都被查找。如果该值大于或等于数组的长度,则整个数组会被查找。如果为负值,将其视为从数组末尾向前的偏移。即使该值为负,数组仍然会被从后向前查找。如果该值为负时,其绝对值大于数组长度,则方法返回 -1,即数组不会被查找。

includes : 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。
arr.includes(searchElement, fromIndex)
fromIndex是可选的,默认为0。从该索引处开始查找 searchElement。如果为负值,则按升序从 array.length - fromIndex 的索引开始搜索。默认为 0。如果数组的长度小于负值,则全部元素都会被遍历。

var a = [1, 2, 3];
a.includes(3, -6); // true
a.includes(3, 7);  // false

toString : 返回一个字符串,表示指定的数组及其元素。 Array对象覆盖了Object的 toString 方法。对于数组对象,toString 方法连接数组并返回一个字符串,其中包含用逗号分隔的每个数组元素。
当一个数组被作为文本值或者进行字符串连接操作时,将会自动调用其 toString 方法。

2 + [1,2,3] // 21,2,3

独立于原型链中的方法

Array.isArray : ie9+,用于确定传递的值是否是一个 Array。
Array.isArray(obj)

// 下面的函数调用都返回 true
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
// 鲜为人知的事实:其实 Array.prototype 也是一个数组。
Array.isArray(Array.prototype); 

// 下面的函数调用都返回 false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray({ __proto__: Array.prototype });

Array.of : 方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。
Array.of(element0[, element1[, ...[, elementN]]])

Array.from : 方法从一个类似数组或可迭代对象中创建一个新的数组实例。
Array.from(arrayLike[, mapFn[, thisArg]])

console.log(Array.from('foo')); //  ['f', 'o', 'o']
console.log(Array.from([1, 2, 3], x => x + x)); // [2, 4, 6]

如果指定了该参数,新数组中的每个元素会执行该回调函数。