JS Array那些事儿

325 阅读8分钟

Array Iterator可遍历对象

entries()

方法返回一个新的Array Iterator对象

什么是Array Iterator对象?

const array1 = ['a', 'b', 'c'];

const iterator1 = array1.entries();

console.log(iterator1.next());
console.log(iterator1.next());
console.log(iterator1.next());
console.log(iterator1.next());

打印结果:

> Object { value: Array [0, "a"], done: false }
> Object { value: Array [1, "b"], done: false }
> Object { value: Array [2, "c"], done: false }
> Object { value: undefined, done: true }

keys()

keys() 方法返回一个包含数组中每个索引键的Array Iterator对象。

const array1 = ['a', 'b', 'c'];
const iterator = array1.keys();

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

输出:

> Object { value: 0, done: false }
> Object { value: 1, done: false }
> Object { value: 2, done: false }
> Object { value: undefined, done: true }

keys()和Object.keys()的区别?

索引迭代器会包含那些没有对应元素的索引,例如:

var arr = ["a", , "c"];
const iterator = array1.keys();
console.log([...iterator])   // [0,1,2]
console.log(Object.keys(arr))  // ['0','1']

values()

返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值

const array1 = ['a', 'b', 'c'];
const iterator = array1.values();

console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

输出:

> Object { value: "a", done: false }
> Object { value: "b", done: false }
> Object { value: "c", done: false }
> Object { value: undefined, done: true }

或者

for (const value of iterator) {
  console.log(value);
}

> "a"
> "b"
> "c"

数组的操作

unshift()

将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组)。

const array1 = [1, 2, 3];

console.log(array1.unshift(4, 5));
//  output: 5

console.log(array1);
//  output:  [4, 5, 1, 2, 3]

shift()

从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。

const array1 = [1, 2, 3];

const firstElement = array1.shift();

console.log(array1);
// output:  [2, 3]

console.log(firstElement);
// output: 1

在while循环中使用shift() shift() 方法经常用于while loop的环境中。下例中每个循环将要从一个数组中移除下一项元素,直至它成为空数组。

var names = ["Andrew", "Edward", "Paul", "Chris" ,"John"];

while( (i = names.shift()) !== undefined ) {
    console.log(i);
}
// Andrew, Edward, Paul, Chris, John

pop()

从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。

const plants = ['broccoli', 'cauliflower', 'cabbage', 'kale', 'tomato'];
plants.pop()
console.log(plants);
//output: Array ["broccoli", "cauliflower", "cabbage", "kale"]

splice()与slice()的区别

slice是截取一段原数组,返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。

arr.slice(begin, end)
  • begin不传,则从0开始;begin大于数组长度,则返回空数组
  • end不传,则到末尾;end大于数组长度,则也到末尾

slice对原数组的拷贝,元素是个对象引用(不是实际的对象),slice 会拷贝这个对象引用到新的数组里。因为两个对象引用都引用了同一个对象,如果被引用的对象发生改变,则两个数组中的此元素都会发生改变。

slice 方法可以用来将一个类数组(Array-like)对象/集合转换成一个新数组。例如:

function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

splice通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组


array.splice(start[, deleteCount[, item1[, item2[, ...]]]])

  • start必填。如果大于数组长度 ,则从末尾开始添加内容;如果是负数,则从倒数第N位;如果负数绝对值大于数组长度,则从0开始
  • deleteCount不传,则 start之后的所有元素都被删除,包含 start;如果为0或负数,则必须添加一个新元素。
  • item1,item2,...,从start开始添加进去的元素,如果不传,则只执行删除操作。

fill()

用一个固定值填充一个数组中从startIndex到endIndex内的全部元素。包括start,不包括end。返回修改后的数组。

arr.fill(value,start,end)
  • start:可选,默认为0
  • end:可选,默认为数组长度
const array1 = [1, 2, 3, 4];

console.log(array1.fill(0, 2, 3)); // output: [1, 2, 0, 4]

console.log(array1.fill(5, 1)); // output: [1, 5, 5, 5]

console.log(array1.fill(6)); // output: [6, 6, 6, 6]

fill 方法故意被设计成通用方法, 该方法不要求 this 是数组对象。如果start 是个负数, 则开始索引会被自动计算成为 length+start, 其中 length 是 this 对象的 length 属性值;end也是如此。

reverse()

颠倒数组中元素的位置,改变了数组,并返回该数组

const array1 = ['one', 'two', 'three'];

console.log(array1.reverse()) //["three", "two", "one"]

数组的遍历

sort()

  • 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
  • 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。
  • 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
  • 返回排序后的数组。请注意,数组已原地排序,并且不进行复制。

every()

所有元素都符合,才会返回true,否则返回false。

[12, 5, 8, 130, 44].every(x => x >= 10); // false

回调函数的参数:

  • element
  • index可选
  • array可选

some()

与every对立,只要有一个符合条件就返回true,所有元素都不符合才会返回false

[12, 5, 8, 1, 4].some(x => x > 10); // true

some和includes的区别

some可以变相实现includes的功能:

function includes(arr, val) {
  return arr.some(arrVal => val === arrVal);
}

includes参数是传入值,判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。

arr.includes(value,fromIndex)
  • fromIndex默认为0;如果为负值,则按升序从 array.length + fromIndex 的索引开始搜。

map()

创建一个新数组,返回一个由原数组每个元素执行回调函数的结果组成的新数组。

  • 因为map生成一个新数组,当你不打算使用返回的新数组却使用map是违背设计初衷的,请用forEach或者for-of替代。
  • 你不该使用map的情况: A)你不打算使用返回的新数组,或/且 B) 你没有从回调函数中返回值
  • callback 函数会被自动传入三个参数:数组元素,元素索引,原数组本身。
  • map 不修改调用它的原数组本身
const array1 = [1, 4, 9, 16];

const map1 = array1.map(x =>  x * 2);

console.log(map1); // output: [2, 8, 18, 32]

数组的展平

flat()

会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。

  • 参数depth,默认为1,Infinity为任意深度。
  • flat() 方法会移除数组中的空项。
// 递归版本的自己实现
function flatten(array) {
  var flattend = [];
  (function flat(array) {
    array.forEach(function(el) {
      if (Array.isArray(el)) flat(el);
      else flattend.push(el);
    });
  })(array);
  return flattend;
}

flatMap()

首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。

返回一个新的数组,其中每个元素都是回调函数的结果,并且结构深度 depth 值为1。

flatMap和map的区别?

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"]

flatMap()其实就是先map()操作然后flat(1)操作。

其他

lastIndexOf()

数组中该元素最后一次出现的索引,如未找到返回-1。从后往前找

arr.lastIndexOf(searchElement,fromIndex)
  • fromIndex默认为arr.length - 1,如果该值大于或等于数组的长度,则整个数组会被查找
  • 如果为负数,将其值为(arr.length + fromIndex)。如果绝对值大于数组长度,则方法返回-1。
const animals = ['Dodo', 'Tiger', 'Penguin', 'Dodo'];
console.log(animals.lastIndexOf('Dodo'));// output: 3
console.log(animals.lastIndexOf('Dodo',-1));// output: 3

join()

将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串

const elements = ['Fire', 'Air', 'Water'];
console.log(elements.join('-')) ;  // output: "Fire-Air-Water"

参数separator可选,指定一个字符串来分隔数组的每个元素。默认为','。如果separator是空字符串(""),则所有元素之间都没有任何字符。

copyWithin()

浅复制数组的一部分到同一数组中的另一个位置,并返回改变后的数组,不会改变原数组的长度。

arr.copyWithin(target, start, end)
  • target是复制序列到这个位置
  • start可选,是复制元素的开始位置,默认为0。如果为负数,则为arr.length+start
  • end可选,复制元素的结束位置,默认为arr.length。如果为负数,则为arr.length+start

reduce()

reduce() 如何运行

假如运行下段reduce()代码:

[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array){
  return accumulator + currentValue;
});

callback 被调用四次,每次调用的参数和返回值如下表:

callbackaccumulatorcurrentValuecurrentIndexarrayreturn value
first call011[0, 1, 2, 3, 4]1
second call122[0, 1, 2, 3, 4]3
third call333[0, 1, 2, 3, 4]6
fourth call644[0, 1, 2, 3, 4]10

由reduce返回的值将是最后一次回调返回值(10)。

你还可以使用箭头函数来代替完整的函数。 下面的代码将产生与上面的代码相同的输出:

[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr );

如果你打算提供一个初始值作为reduce()方法的第二个参数,以下是运行过程及结果:

[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => { return accumulator + currentValue; }, 10 );
callbackaccumulatorcurrentValuecurrentIndexarrayreturn value
first call1000[0, 1, 2, 3, 4]10
second call1011[0, 1, 2, 3, 4]11
third call1122[0, 1, 2, 3, 4]13
fourth call1333[0, 1, 2, 3, 4]16
fifth call1644[0, 1, 2, 3, 4]20

这种情况下reduce()返回的值是20。