数据类型 - Array

什么是数组

Array对象是用于构造数组的全局对象,数组是类似于列表的高阶对象。 数组是特殊的对象数据类型

  • 中括号中设置的是属性值,它的属性名是默认生成的数字,从0开始递增,而且这个数字代表每一项的位置,我们把其称之为“索引” =>从0开始,连续递增,代表每一项位置的数字属性名
  • 默认有一个属性名length,存储数组的长度
  • 数组由中括号构成,其中包含用逗号分隔的元素列表。
  • 数组中可以存储任何类型的的元素:字符串,数字,对象,另一个变量,甚至另一个数组,可以混合匹配

创建数组

  • 字面量方法:
    • [element0, element1, …, elementN]
    • var fruits = ['Apple', 'Banana'];
  • 函数方法
    • new Array(element0, element1[, …[, elementN]])
    • new Array(arrayLength)
      • elementN: Array构造器会根据给定的元素创建一个数组,当仅有一个参数且为数字时除外
      • arrayLength:一个范围在 0 到 232-1 之间的整数,数组的长度
      • 如果传入的参数不是有效值,则会抛出 RangeError 异常
    • 描述:
      • 只能用整数作为数组元素的索引,而不能用字符串。后者称为关联数组
      • 使用非整数并通过方括号或点号来访问或设置数组元素时,所操作的并不是数组列表中的元素,而是数组对象的属性集合上的变量
      • 数组对象的属性和数组元素列表是分开存储的,并且数组的遍历和修改操作也不能作用于这些命名属性

访问和修改数组

  • 使用括号表示法访问数组中的元素(与检索特定字符串字符的方法相同)
  • 数组的索引是从0开始的,第一个元素的索引为0,最后一个元素的索引等于该数组的长度减1
  • 如果指定的索引是一个无效值,JavaScript 数组并不会报错,而是会返回 undefined
  • 在 JavaScript 中,以数字开头的属性不能用点号引用,必须用方括号
  • 如果对象的属性名是保留字(最好不要这么做!),只能通过字符串的形式用方括号来访问
  • array[n] = “newString” ,用 “newString” 替换 array[n] 位置上的原来的元素
  • 数组中若包含数组,则称之为多维数组,访问元素的方式ary[1][2]:访问第二项中第三项元素
var arr = ['first element', 'second element', 'last element'];
console.log(arr[0]);              // 打印 'first element'
console.log(arr[1]);              // 打印 'second element'
console.log(arr[arr.length - 1]); // 打印 'last element'
console.log(arr[4]);    // 打印 "undefined"
console.log(arr.0);     // SyntaxError

arr[1] = "haha";
console.log(arr);//['first element', 'haha', 'last element']

var promise = {
  'var'  : 'text',
  'array': [1, 2, 3, 4]
};
console.log(promise['var']);//'text'

length 和数字下标之间的关系

  • length:获取数组的长度
  • JavaScript 数组的 length 属性和其数字下标之间有着紧密的联系
  • 使用一个合法的下标为数组元素赋值,并且该下标超出了当前数组的大小的时候,解释器会同时修改 length 的值
  • 也可以显式地给 length 赋一个更大的值
  • 为 length 赋一个更小的值则会删掉一部分元素
  • length属性也有其他用途,最常用于循环,即循环遍历数组中的所有项
var fruits = [];
fruits.push('banana', 'apple', 'peach');
console.log(fruits.length); // 3

fruits[5] = 'mango';
console.log(fruits[5]); // 'mango'
console.log(Object.keys(fruits));  // ['0', '1', '2', '5']
console.log(fruits.length); // 6
console.log(fruits);  // ["banana", "apple", "peach", empty × 2, "mango"]
console.log(fruits[4]); // undefined
/*
0: "banana"
1: "apple"
2: "peach"
5: "mango"
length: 6
*/

fruits.length = 10;
console.log(Object.keys(fruits)); // ['0', '1', '2', '5']
console.log(fruits.length); // 10

fruits.length = 2;
console.log(Object.keys(fruits)); // ['0', '1']
console.log(fruits.length); // 2

let ary= [1, 1, 2, 3, 5, 8, 13];
for (let i = 0; i < ary.length; i++) {
  console.log(ary[i]);
}

数组的方法

数组对象的方法

  • Array.from:从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例

    • Array.from(arrayLike[, mapFn[, thisArg]])
      • arrayLike:想要转换成数组的伪数组对象或可迭代对象
      • mapFn 可选:如果指定了该参数,新数组中的每个元素会执行该回调函数
      • thisArg 可选:可选参数,执行回调函数 mapFn 时 this 对象
    • 返回值:一个新的数组实例
    • 描述:
      • 伪数组对象(拥有一个 length 属性和若干索引属性的任意对象)
      • 可迭代对象(可以获取对象中的元素,如 Map和 Set 等)
      • from() 的 length 属性为 1 ,即 Array.from.length === 1
  • Array.isArray:用来判断某个变量是否是一个数组对象

    • Array.isArray(obj)
      • 返回值:如果值是 Array,则为true; 否则为false。
        // 下面的函数调用都返回 true
        Array.isArray([]);
        Array.isArray([1]);
        Array.isArray(new Array());
        Array.isArray(new Array('a', 'b', 'c', 'd'))
        // 鲜为人知的事实:其实 Array.prototype 也是一个数组。
        Array.isArray(Array.prototype);
    
  • Array.of:根据一组参数来创建新的数组实例,支持任意的参数数量和类型

    • Array.of(element0[, element1[, …[, elementN]]])
      • elementN:任意个参数,将按顺序成为返回数组中的元素
      • 返回值:新的 Array 实例
        Array.of(1);         // [1]
        Array.of(1, 2, 3);   // [1, 2, 3]
        Array.of(undefined); // [undefined]
        //兼容废旧环境
        if (!Array.of) {
          Array.of = function() {
            return Array.prototype.slice.call(arguments);
          };
        }
    

字符串和数组之间的转换

字符串转换为数组

let str = "a,s,d,f,g,h,j,k,l";
//arr.join([separator]) [separator]默认是逗号分割,也可以传入其他分隔符
let ary = str.split(",");//[a,s,d,f,g,h,j,k,l]

数组转换为字符串

let ary = [a,s,d,f,g,h,j,k,l];

//arr.join([separator]) [separator]:隔数组元素的指定字符串,默认是逗号,也可以传其他字符串
// undefined 或 null,会被转换为空字符串
let str = ary.join();//

数组实例的方法

  • 不修改原数组:concat(合并)、copyWithin(浅复制)、fill(填充)、includes(包含)、indexOf(索引)、join(拼接)、slice(截取)、toString(转字符串)
  • 修改原数组:flat(递归)、pop(后删)、push(后加)、unshift(前加)、shift(前删)、reverse(颠倒)sort(排序)、splice(增删改)
  • 遍历数组:every、filter、forEach、entries/keys/values(迭代器)、map、reduce/reduceRight、some/find / findIndex/lastIndexOf

数组的增删改查

push

在数组的末尾增加一个或多个元素,并返回数组的新长度

  • arr.push(element1, …, elementN)
    • elementN:被添加到数组末尾的元素
  • 返回值:当调用该方法时,新的 length 属性值将被返回
  • 描述:
    • 可以和 call() 或 apply() 一起使用时,可应用在类似数组的对象上
    • push 方法根据 length 属性来决定从哪里开始插入给定的值
    • 如果 length 不能被转成一个数值,则插入的元素索引为 0,包括 length 不存在时
    • 当 length 不存在时,将会创建它。
var sports = ["soccer", "baseball"];
var total = sports.push("football", "swimming");
console.log(sports);// ["soccer", "baseball", "football", "swimming"]
console.log(total);// 4

var vegetables = ['parsnip', 'potato'];
var moreVegs = ['celery', 'beetroot'];
// 将第二个数组融合进第一个数组,相当于 vegetables.push('celery', 'beetroot');
Array.prototype.push.apply(vegetables, moreVegs);
console.log(vegetables);// ['parsnip', 'potato', 'celery', 'beetroot']

var obj = {
    length: 0,
    addElem: function addElem (elem) { [].push.call(this, elem)}
}
obj.addElem({});
obj.addElem({});
console.log(obj.length);// → 2
pop

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

  • arr.pop()
  • 返回值:从数组中删除的元素(当数组为空时返回undefined)
  • 描述:
    • 可以和 call() 或 apply() 一起使用时,可应用在类似数组的对象上
    • pop方法根据 length属性来确定最后一个元素的位置
    • 如果不包含length属性或length属性不能被转成一个数值,会将length置为0,并返回undefined
    • 如果在一个空数组上调用 pop(),返回 undefined。
let myFish = ["angel", "clown", "mandarin", "surgeon"];
let popped = myFish.pop();
console.log(myFish);// ["angel", "clown", "mandarin"]
console.log(popped);// "surgeon"
shift

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

  • arr.shift()
  • 返回值 :从数组中删除的元素; 如果数组为空则返回undefined 。
  • 描述:
    • shift 方法移除索引为0的元素(即第一个元素),并返回被移除的元素,其他元素的索引值随之减 1。如果 length 属性的值为 0 (长度为 0),则返回 undefined。
    • 能够通过 call 或 apply 方法作用于类似数组的对象上。但是对于没有 length 属性(从0开始的一系列连续的数字属性的最后一个)的对象,调用该方法可能没有任何意义。
var myFish = ['angel', 'clown', 'mandarin', 'surgeon'];
console.log(JSON.stringify(myFish));// ['angel', 'clown', 'mandarin', 'surgeon']
var shifted = myFish.shift();
console.log( myFish);//['clown', 'mandarin', 'surgeon']
console.log(shifted);//angel

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

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

  • arr.unshift(element1, …, elementN)
    • elementN:要添加到数组开头的元素或多个元素
  • 返回值:当一个对象调用该方法时,返回其 length 属性值。
  • 描述:
    • unshift 方法会在调用它的类数组对象的开始位置插入给定的参数
    • 能够通过 call 或 apply 方法作用于类数组对象上
    • 对于没有length属性的对象,调用该方法可能没有任何意义。
    • 如果传入多个参数,它们会被以块的形式插入到对象的开始位置,它们的顺序和被作为参数传入时的顺序一致
    • 传入多个参数调用一次unshift,和传入一个参数调用多次unshift(例如,循环调用),它们将得到不同的结果。
let arr = [4,5,6];
arr.unshift(1,2,3);
console.log(arr); // [1, 2, 3, 4, 5, 6]

arr = [4,5,6]; // 重置数组
arr.unshift(1);
arr.unshift(2);
arr.unshift(3);
console.log(arr); // [3, 2, 1, 4, 5, 6]

arr = [1, 2];
arr.unshift(0); // arr is [0, 1, 2]
arr.unshift(-2, -1); //  arr is [-2, -1, 0, 1, 2] => length = 5
arr.unshift([-4, -3]);// arr is [[-4, -3], -2, -1, 0, 1, 2] =>length = 6
arr.unshift([-7, -6], [-5]); //arr is [ [-7, -6], [-5], [-4, -3], -2, -1, 0, 1, 2 ] =>length = 8
splice

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

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

    • start:指定修改的开始位置(从0计数)。
      • 如果超出了数组的长度,则从数组末尾开始添加内容;
      • 如果是负值,则表示从数组末位开始的第几位(从-1计数,这意味着-n是倒数第n个元素并且等价于array.length-n);
      • 如果负数的绝对值大于数组的长度,则表示开始位置为第0位。
    • deleteCount 可选:整数,表示要移除的数组元素的个数。
      • 如果 deleteCount 大于 start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。
      • 如果 deleteCount 被省略了,或者它的值大于等于array.length - start(也就是说,如果它大于或者等于start之后的所有元素的数量),那么start之后数组的所有元素都会被删除。
      • 如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。
    • item1,item2,…可选:要添加进数组的元素,从start位置开始。如果不指定,则splice()将只删除数组元素。
  • 返回值:由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。

  • 描述:如果添加进数组的元素个数不等于被删除的元素个数,数组的长度会发生相应的改变。

//从第 2 位开始删除 0 个元素,插入“drum”
var myFish = ["angel", "clown", "mandarin", "sturgeon"];
var removed = myFish.splice(2, 0, "drum");
console.log( myFish); // ["angel", "clown", "drum", "mandarin", "sturgeon"]
console.log(removed); // [], 没有元素被删除


myFish = ['angel', 'clown', 'drum', 'mandarin', 'sturgeon'];
removed = myFish.splice(3, 1);
// 运算后的 myFish: ["angel", "clown", "drum", "sturgeon"]
// 被删除的元素: ["mandarin"]

slice

抽取当前数组中的一段元素组合成一个新数组,含首不含尾,且不改变原数组。

  • arr.slice([begin[, end]])
    • begin 可选:
      • 提取起始处的索引(从 0 开始),从该索引开始提取原数组元素。
      • 如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取
      • 如果省略 begin,则 slice 从索引 0 开始。
      • 如果 begin 超出原数组的索引范围,则会返回空数组。
    • end 可选:
      • 提取终止处的索引(从 0 开始),在该索引处结束提取原数组元素
      • slice 会提取原数组中索引从 begin 到 end 的所有元素(包含 begin,但不包含 end)。
      • 如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。
      • 如果 end 被省略,则 slice 会一直提取到原数组末尾。
      • 如果 end 大于数组的长度,slice 也会一直提取到原数组末尾。
  • 返回值:一个含有被提取元素的新数组。
  • 描述:slice不会修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。
var fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
var citrus = fruits.slice(1, 3);
// fruits contains ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']
// citrus contains ['Orange','Lemon']

// 使用 slice 方法从 myCar 中创建一个 newCar。
var myHonda = { color: 'red', wheels: 4, engine: { cylinders: 4, size: 2.2 } };
var myCar = [myHonda, 2, "cherry condition", "purchased 1997"];
var newCar = myCar.slice(0, 2);
// 输出 myCar、newCar 以及各自的 myHonda 对象引用的 color 属性。
console.log(' myCar = ' + JSON.stringify(myCar));// myCar = [{"color":"red","wheels":4,"engine":{"cylinders":4,"size":2.2}},2,"cherry condition","purchased 1997"]
console.log('newCar = ' + JSON.stringify(newCar));//newCar = [{"color":"red","wheels":4,"engine":{"cylinders":4,"size":2.2}},2]
console.log(' myCar[0].color = ' + JSON.stringify(myCar[0].color));// myCar[0].color = "red"
console.log('newCar[0].color = ' + JSON.stringify(newCar[0].color));//VM109:1 newCar[0].color = "red"

var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);
function list() {  return slice(arguments) }
var list1 = list(1, 2, 3); // [1, 2, 3]

(function () {
  'use strict';
  var _slice = Array.prototype.slice;
  try {
    _slice.call(document.documentElement);
  } catch (e) { 
    Array.prototype.slice = function(begin, end) {
      end = (typeof end !== 'undefined') ? end : this.length;
      if (Object.prototype.toString.call(this) === '[object Array]'){
        return _slice.call(this, begin, end);
      };
      var i, cloned = [],size, len = this.length, start = begin || 0;
      start = (start >= 0) ? start : Math.max(0, len + start);
      var upTo = (typeof end == 'number') ? Math.min(end, len) : len;
      if (end < 0) {upTo = len + end;    }
      size = upTo - start;
      if (size > 0) {
        cloned = new Array(size);
        if (this.charAt) {
          for (i = 0; i < size; i++) { cloned[i] = this.charAt(start + i) }
        } else {
          for (i = 0; i < size; i++) { cloned[i] = this[start + i]  }
        }
      }
      return cloned;
    };
  }
}());
fill

用一个固定值填充数组中从起始索引到终止索引内的全部元素,不包括终止索引

  • arr.fill(value[, start[, end]])
    • value:用来填充数组元素的值
    • start 可选:始索引,默认值为0
    • end 可选:终止索引,默认值为 this.length
  • 返回值:修改后的数组
  • 描述:
    • 该方法不要求 this 是数组对象
    • 会改变调用它的 this 对象本身, 然后返回它, 而并不是返回一个副本
    • 如果 start 是个负数, 则开始索引会被自动计算成为 length+start
    • 如果 end 是个负数, 则结束索引会被自动计算成为 length+end
[1, 2, 3].fill(4);               // [4, 4, 4]
[1, 2, 3].fill(4, 1);            // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2);         // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1);         // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3);         // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2);       // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN);     // [1, 2, 3]
[1, 2, 3].fill(4, 3, 5);         // [1, 2, 3]
Array(3).fill(4);                // [4, 4, 4]
[].fill.call({ length: 3 }, 4);  // {0: 4, 1: 4, 2: 4, length: 3}

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

if (!Array.prototype.fill) {
  Object.defineProperty(Array.prototype, 'fill', {
    value: function(value) {
      // Steps 1-2.
      if (this == null) {throw new TypeError('this is null or not defined');}
      var O = Object(this),len = O.length >>> 0;
      // Steps 6-7.
      var start = arguments[1], relativeStart = start >> 0;
      // Step 8.
      var k = relativeStart < 0 ?
        Math.max(len + relativeStart, 0) :
        Math.min(relativeStart, len);
      // Steps 9-10.
      var end = arguments[2],relativeEnd = end === undefined ? len : end >> 0;
      // Step 11.
      var final = relativeEnd < 0?
        Math.max(len + relativeEnd, 0) :
        Math.min(relativeEnd, len);
      // Step 12.
      while (k < final) { O[k] = value; k++; }
      // Step 13.
      return O;
    }
  });
}
indexOf

返回数组中第一个(/最后一个[从右边数第一个])与指定值相等的元素的索引,如果找不到这样的元素,则返回 -1

  • arr.indexOf(searchElement[, fromIndex])
  • searchElement:要查找的元素
  • fromIndex 可选:开始查找的位置
    • fromIndex>length 返回-1
    • fromIndex < 0 ,则从(length - fromIndex)处开始查找。
    • 如果(length - fromIndex)< 0 ,则整个数组都将会被查询。其默认值为0.
  • 返回值 : 首个被找到的元素在数组中的索引位置; 若没有找到则返回 -1
    var array = [2, 5, 9];
    array.indexOf(2);     // 0
    array.indexOf(7);     // -1
    array.indexOf(9, 2);  // 2
    array.indexOf(2, -1); // -1
    array.indexOf(2, -3); // 0

lastIndexOf

方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从 fromIndex 处开始。

  • arr.lastIndexOf(searchElement[, fromIndex])
  • searchElement:被查找的元素。
  • fromIndex 可选:从此位置开始逆向查找。
    • 默认为数组的长度减 1(arr.length - 1),即整个数组都被查找
    • 如果该值大于或等于数组的长度,则整个数组会被查找
    • 如果为负值,将其视为从数组末尾向前的偏移。
    • 即使该值为负,数组仍然会被从后向前查找
    • 如果该值为负时,其绝对值大于数组长度,则方法返回 -1,即数组不会被查找。
  • 返回值:数组中该元素最后一次出现的索引,如未找到返回-1
var array = [2, 5, 9, 2];
var index = array.lastIndexOf(2);// index is 3
index = array.lastIndexOf(7);// index is -1
index = array.lastIndexOf(2, 3);// index is 3
index = array.lastIndexOf(2, 2);// index is 0
index = array.lastIndexOf(2, -2);// index is 0
index = array.lastIndexOf(2, -1);// index is 3

if (!Array.prototype.lastIndexOf) {
  Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) {
    'use strict';
    if (this === void 0 || this === null) throw new TypeError();
    var n, k, t = Object(this), len = t.length >>> 0;
    if (len === 0) return -1;

    n = len - 1;
    if (arguments.length > 1) {
      n = Number(arguments[1]);
      if (n != n) {
        n = 0;
      } else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) {
        n = (n > 0 || -1) * Math.floor(Math.abs(n));
      }
    }
    for (k = n >= 0? Math.min(n, len - 1) : len - Math.abs(n); k >= 0; k--) {
      if (k in t && t[k] === searchElement)  return k;
    }
    return -1;
  };
}

数组的排序

sort

对数组元素进行排序,并返回当前数组

  • 用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的
  • 由于它取决于具体实现,因此无法保证排序的时间和空间复杂性。
  • arr.sort([compareFunction])
    • compareFunction可选 : 用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的各个字符的Unicode位点进行排序。
      • firstEl:第一个用于比较的元素。
      • secondEl:第二个用于比较的元素。
  • 返回值:排序后的数组。请注意,数组已原地排序,并且不进行复制。
  • 描述:
    • compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前
    • compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变
    • 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前
    • compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);// expected output: Array [1, 100000, 21, 30, 4]

var numbers = [4, 2, 5, 1, 3];
numbers.sort((a, b) => a - b);
console.log(numbers);// [1, 2, 3, 4, 5]

var items = [ { name: 'Edward', value: 21 },  { name: 'Sharpe', value: 37 },
              { name: 'And', value: 45 },  { name: 'The', value: -12 },
              { name: 'Magnetic' },  { name: 'Zeros', value: 37 }];
items.sort(function (a, b) {  return (a.value - b.value)});// sort by value
items.sort(function(a, b) {// sort by name
  var nameA = a.name.toUpperCase(); // ignore upper and lowercase
  var nameB = b.name.toUpperCase(); // ignore upper and lowercase
  if (nameA < nameB) {    return -1;  }
  if (nameA > nameB) {    return 1;  }
  return 0;// names must be equal
});
reverse

颠倒数组中元素的排列顺序,即原先的第一个变为最后一个,原先的最后一个变为第一个

  • arr.reverse()
  • 返回值:颠倒后的数组。
  • 描述:
    • reverse 方法颠倒数组中元素的位置,改变了数组,并返回该数组的引用
    • 可被 called 或 applied于类似数组对象。
    • 对于没有length属性的对象,调用该方法可能没有任何意义。
let a = [1, 2, 3];
console.log(a); // [1, 2, 3]
a.reverse();
console.log(a); // [3, 2, 1]

a = {0: 1, 1: 2, 2: 3, length: 3};
console.log(a); // {0: 1, 1: 2, 2: 3, length: 3}
Array.prototype.reverse.call(a); //same syntax for using apply()
console.log(a); // {0: 3, 1: 2, 2: 1, length: 3}

数组的递归

flat

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

  • var newArray = arr.flat([depth])
    • depth 可选:指定要提取嵌套数组的结构深度,默认值为 1
  • 返回值:一个包含将数组与子数组中所有元素的新数组
const arr1 = [0, 1, 2, [3, 4]];
console.log(arr2.flat(2)); // expected output: [0, 1, 2, [3, 4]]

var arr4 = [1, 2, , 4, 5];
arr4.flat();// [1, 2, 4, 5]

//替代方案
var arr = [1, 2, [3, 4]];
// 展开一层数组
arr.flat(); //[1,2,3,4]
// 等效于
arr.reduce((acc, val) => acc.concat(val), []);// [1, 2, 3, 4]

// 使用扩展运算符 ...
const flattened = arr => [].concat(...arr);
flatMap

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

  • 语法:
var new_ary = arr.flatMap(function callback(currentValue[, index[, array]]) {
	 // return element for new_array
}[, thisArg]);
  • callback:可以生成一个新数组中的元素的函数,可以传入三个参数:
    • currentValue:当前正在数组中处理的元素
    • index可选:可选的。数组中正在处理的当前元素的索引。
    • array可选:可选的。被调用的 map 数组
    • thisArg可选:可选的。执行 callback 函数时 使用的this 值。
  • 返回值: 一个新的数组,其中每个元素都是回调函数的结果,并且结构深度 depth 值为1。
var arr1 = [1, 2, 3, 4];
arr1.map(x => [x * 2]);// [[2], [4], [6], [8]]
arr1.flatMap(x => [x * 2]);// [2, 4, 6, 8]
// only one level is flattened
arr1.flatMap(x => [[x * 2]]);// [[2], [4], [6], [8]]

数组拼接

concat

返回一个由当前数组和其它若干个数组或者若干个非数组值组合而成的新数组

  • var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
  • valueN可选:数组和/或值,将被合并到一个新的数组中
    • 如果省略了所有valueN参数,则concat会返回调用此方法的现存数组的一个浅拷贝
  • 返回值:新的 Array 实例
  • concat方法不会改变this或任何作为参数提供的数组,而是返回一个浅拷贝,它包含与原始数组相结合的相同元素的副本
var alpha = ['a', 'b', 'c'];
var numeric = [1, 2, 3];
alpha.concat(numeric);// result in ['a', 'b', 'c', 1, 2, 3]

var num1 = [1, 2, 3],
    num2 = [4, 5, 6],
    num3 = [7, 8, 9];
var nums = num1.concat(num2, num3);
console.log(nums);// results in [1, 2, 3, 4, 5, 6, 7, 8, 9]

var alpha = ['a', 'b', 'c'];
var alphaNumeric = alpha.concat(1, [2, 3]);
console.log(alphaNumeric);// results in ['a', 'b', 'c', 1, 2, 3]

var num1 = [[1]];
var num2 = [2, [3]];
var num3=[5,[6]];
var nums = num1.concat(num2);
console.log(nums);// results is [[1], 2, [3]]
var nums2=num1.concat(4,num3);
console.log(nums2); // results is [[1], 4, 5,[6]]

数组的拷贝

copyWithin

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

  • arr.copyWithin(target[, start[, end]])
    • target:复制序列到该位置。
      • 如果是负数,target将从末尾开始计算
      • 如果 target 大于等于 arr.length,将会不发生拷贝
      • 如果 target 在 start 之后,复制的序列将被修改以符合 arr.length
    • start:0 为基底的索引,开始复制元素的起始位置
      • 如果是负数,start 将从末尾开始计算
      • 如果 start 被忽略,copyWithin 将会从0开始复制
    • end: 开始复制元素的结束位置
      • copyWithin将会拷贝到该位置,但不包括 end 这个位置的元素
      • 如果是负数, end 将从末尾开始计算
      • 如果end被忽略,将一直复制到数组结尾
  • 返回值:改变后的数组
  • 参数 target、start 和 end 必须为整数
  • start 为负,则其指定的索引位置等同于 length+start
  • 不会改变this的长度length,但是会改变this本身的内容,且需要时会创建新的属性
[1, 2, 3, 4, 5].copyWithin(-2);// [1, 2, 3, 1, 2]
[1, 2, 3, 4, 5].copyWithin(0, 3);// [4, 5, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(0, 3, 4);// [4, 2, 3, 4, 5]
[].copyWithin.call({length: 5, 3: 1}, 0, 3);// {0: 1, 3: 1, length: 5}

数组的迭代方法

数组的迭代方法一般用来办理数组中的每一项做一些特殊处理, 有很多方法都需要指定一个回调函数作为参数,在每一个数组元素都分别执行完回调函数之前,数组的length属性会被缓存在某个地方,所以,如果你在回调函数中为当前数组添加了新的元素,那么那些新添加的元素是不会被遍历到的。所以不要在遍历过程中对原数组进行任何修改(但为了可读性和可维护性),

forEach

为数组中的每个元素执行一次回调函数

  • arr.forEach(callback(currentValue [, index [, array]])[, thisArg])
    • callback:用来测试每个元素的函数,它可以接收三个参数:
      • element:用于测试的当前值
      • index可选:数组中正在处理的当前元素的索引
      • array可选:forEach() 方法正在操作的数组
    • thisArg 可选:可选参数。当执行回调函数 callback 时,用作 this 的值
    • 返回值:undefined
  • 描述:
    • 按升序为数组中含有效值的每一项执行一次callback函数,已删除或者未初始化的项将被跳过
    • 如果省略thisArg参数,或者其值为null或undefined,this则指向全局对象
    • forEach() 为每个数组元素执行一次 callback 函数;与 map() 或者 reduce() 不同的是,它总是返回 undefined 值,并且不可链式调用
    • 除了抛出异常以外,没有办法中止或跳出forEach循环。如果你需要中止或跳出循环,forEach方法不是应当使用的工具
    • 需要提前终止循环,可以使用:
      • 一个简单的 for 循环
      • for…of / for…in 循环
      • every()
      • some()
      • find()
      • findIndex()
      • 只要条件允许,也可以使用 filter() 提前过滤出需要遍历的部分,再用 forEach() 处理。
const arraySparse = [1,3,,7];
let numCallbackRuns = 0;
arraySparse.forEach(function(element){ console.log(element); numCallbackRuns++;});
console.log("numCallbackRuns: ", numCallbackRuns);
// 1
// 3
// 7
// numCallbackRuns: 3

// 将for循环转换为forEach
const items = ['item1', 'item2', 'item3'],copy = [];
// before
for (let i=0; i<items.length; i++) { copy.push(items[i]);}
// after
items.forEach(function(item){  copy.push(item);});
map

返回一个由回调函数的返回值组成的新数组

  • 语法:
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
 // Return element for new_array 
}[, thisArg])
  • callback:生成新数组元素的函数,使用三个参数:
    • currentValue:callback 数组中正在处理的当前元素。
    • index可选:callback 数组中正在处理的当前元素的索引。
    • array可选:map 方法调用的数组。
  • thisArg可选:执行 callback 函数时值被用作this。
  • 返回值:一个由原数组每个元素执行回调函数的结果组成的新数组
  • 描述:
    • callback 每次执行后的返回值(包括 undefined)组合起来形成一个新数组
    • callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。
var numbers = [1, 4, 9];
var doubles = numbers.map(function(num) {  return num * 2;});
// doubles数组的值为: [2, 8, 18]
// numbers数组未被修改: [1, 4, 9]

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

如果数组中的每个元素都满足测试函数,则返回 true,否则返回 false

  • arr.every(callback(element[, index[, array]])[, thisArg])
    • callback:用来测试每个元素的函数,它可以接收三个参数:
      • element:用于测试的当前值
      • index可选:用于测试的当前值的索引
      • array可选:调用 every 的当前数组
    • thisArg:执行 callback 时使用的 this 值
  • 返回值:如果回调函数的每一次返回都为 truthy 值,返回 true ,否则返回 false
  • 描述:
    • 若收到一个空数组,此方法在一切情况下都会返回 true
    • every为数组的每个元素执行一次callback函数,直到找到一个使 callback返回falsy的元素
      • 如果发现了一个这样的元素,every 方法将会立即返回 false
      • callback 为每一个元素返回 true,every 就会返回 true
    • every 不会改变原数组
//检测数组中的所有元素是否都大于 10
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, 5, 8, 130, 44].every(x => x >= 10); // false
[12, 54, 18, 130, 44].every(x => x >= 10); // true

//兼容旧环境
if (!Array.prototype.every) {
  Array.prototype.every = function(callbackfn, thisArg) {
    'use strict';
    var T, k;
    if (this == null) { throw new TypeError('this is null or not defined'); };
    var O = Object(this),len = O.length >>> 0;
    if (typeof callbackfn !== 'function') { throw new TypeError();  }
    if (arguments.length > 1) {  T = thisArg;  }
    k = 0;
    while (k < len) {
      var kValue;
      if (k in O) {
        kValue = O[k];
        var testResult = callbackfn.call(T, kValue, k, O);
        if (!testResult) { return false;}
      }
      k++;
    }
    return true;
  };
}
some

如果数组中至少有一个元素满足测试函数,则返回 true,否则返回 false

  • arr.some(callback(element[, index[, array]])[, thisArg])
    • callback:用来测试每个元素的函数,接受三个参数:
      • element:数组中正在处理的元素。
      • index 可选:数组中正在处理的元素的索引值。
      • array可选:some()被调用的数组。
    • thisArg可选:执行 callback 时使用的 this 值。
  • 返回值:数组中有至少一个元素通过回调函数的测试就会返回true;所有元素都没有通过回调函数的测试返回值才会为false。
  • 描述:
    • 如果用一个空数组进行测试,在任何情况下它返回的都是false。
var fruits = ['apple', 'banana', 'mango', 'guava'];
function checkAvailability(arr, val) {
  return arr.some(function(arrVal) {
    return val === arrVal;
  });
};
checkAvailability(fruits, 'kela');   // false
checkAvailability(fruits, 'banana'); // true
filter

将所有在过滤函数中返回 true 的数组元素放进一个新数组中并返回

  • var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
    • callback:用来测试数组的每个元素的函数。返回true表示该元素通过测试,保留该元素,false则不保留。它接受以下三个参数:
      • element:数组中当前正在处理的元素
      • index可选:正在处理的元素在数组中的索引
      • array可选:调用了 filter 的数组本身
    • thisArg可选:执行 callback 时,用于 this 的值
      • 如果提供thisArg参数,则被作为callback被调用时的this值。
      • 否则,callback的this值在非严格模式下是全局对象,严格模式下为undefined
  • 返回值:一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组
//1. 过滤掉小于10的数字
function isBigEnough(element) {  return element >= 10;}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);// filtered is [12, 130, 44]
//2. 过滤数组
var fruits = ['apple', 'banana', 'grapes', 'mango', 'orange'];
function filterItems(query) {
  return fruits.filter(function(el){
    return el.toLowerCase().indexOf(query.toLowerCase()) > -1;})
};
console.log(filterItems('ap')); // ['apple', 'grapes']
console.log(filterItems('an')); // ['banana', 'mango', 'orange']

//兼容版本
if (!Array.prototype.filter){
  Array.prototype.filter = function(func, thisArg) {
    'use strict';
    if (!(typeof func==='function' && this)) throw new TypeError();

    var len = +this.length, res = new Array(len), t = this, c = 0, i = -1;
    if (thisArg === undefined){
      while (++i !== len){
        if (i in this){  if (func(t[i], i, t)){res[c++] = t[i]; }  }
      }
    }else{
      while (++i !== len){// checks to see if the key was set
        if (i in this){if (func.call(thisArg, t[i], i, t)){res[c++] = t[i];}}
      }
    }
    res.length = c; // shrink down array to proper size
    return res;
  };
}
find

找到第一个满足测试函数的元素并返回那个元素的值,如果找不到,则返回undefined

  • arr.find(callback[, thisArg])
    • callback:在数组每一项上执行的函数,接收 3 个参数
      • element:当前遍历到的元素
      • index可选:当前遍历到的索引
      • array可选:数组本身
    • thisArg可选:执行回调时用作this 的对象
  • 返回值:数组中第一个满足所提供测试函数的元素的值,否则返回 undefined
const array1 = [5, 12, 8, 130, 44];
const found = array1.find(element => element > 10);
console.log(found);// expected output: 12

var inventory = [
    {name: 'apples', quantity: 2},
    {name: 'bananas', quantity: 0},
    {name: 'cherries', quantity: 5}
];
function findCherries(fruit) {    return fruit.name === 'cherries';}
console.log(inventory.find(findCherries)); // { name: 'cherries', quantity: 5 }
  • findIndex() 方法,它返回数组中找到的元素的索引,而不是其值
    • 要找到一个元素的位置或者一个元素是否存在于数组中,使用Array.prototype.indexOf() 或 Array.prototype.includes()
var inventory = [
    {name: 'apples', quantity: 2},
    {name: 'bananas', quantity: 0},
    {name: 'cherries', quantity: 5}
];
function findCherries(fruit) { return fruit.name === 'cherries';}
console.log(inventory.find(findCherries)); // { name: 'cherries', quantity: 5 }
//寻找数组中的质数
function isPrime(element, index, array) {
  var start = 2;
  while (start <= Math.sqrt(element)) {
    if (element % start++ < 1) { return false;  }
  }
  return element > 1;
}
console.log([4, 6, 8, 12].find(isPrime)); // undefined, not found
console.log([4, 5, 8, 12].find(isPrime)); // 5
findIndex

找到第一个满足测试函数的元素并返回那个元素的索引,如果找不到,则返回 -1

  • arr.findIndex(callback[, thisArg])
    • callback:针对数组中的每个元素, 都会执行该回调函数, 执行时会自动传入下面三个参数:
      • element:当前元素
      • index:当前元素的索引
      • array:调用findIndex的数组
    • thisArg:可选。执行callback时作为this对象的值
  • 返回值:数组中通过提供测试函数的第一个元素的索引。否则,返回-1
  • 如果callback从不返回真值,或者数组的length为0,则findIndex返回-1
//查找数组中首个质数元素的索引
function isPrime(element, index, array) {
  var start = 2;
  while (start <= Math.sqrt(element)) { if (element % start++ < 1) { return false;}
  }
  return element > 1;
}
console.log([4, 6, 8, 12].findIndex(isPrime)); // -1, not found
console.log([4, 6, 7, 12].findIndex(isPrime)); // 2

if (!Array.prototype.findIndex) {
  Object.defineProperty(Array.prototype, 'findIndex', {
    value: function(predicate) {
      if (this == null) { throw new TypeError('"this" is null or not defined');}
      var o = Object(this);
      var len = +o.length;
      if (typeof predicate !== 'function') { throw new TypeError('predicate must be a function');}
      var thisArg = arguments[1],k = 0;
      while (k < len) {
        var kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) { return k; }
        k++;
      }
      return -1;
    }
  });
}
reduce

从左到右为每个数组元素执行一次回调函数,并把上次回调函数的返回值放在一个暂存器中传给下次回调函数,并返回最后一次回调函数的返回值

  • 语法 : arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
    • callback:执行数组中每个值 (如果没有提供initialValue则第一个值除外)的函数,包含四个参数:
      • accumulator:累计器累计回调的返回值;
        • 它是上一次调用回调时返回的累积值,或initialValue。
      • currentValue:数组中正在处理的元素。
      • index 可选:数组中正在处理的当前元素的索引。
        • 如果提供了initialValue,则起始索引号为0,否则从索引1起始。
      • array可选:调用reduce()的数组
    • initialValue可选:作为第一次调用 callback函数时的第一个参数的值。
      • 如果没有提供初始值,则将使用数组中的第一个元素。
      • 在没有初始值的空数组上调用 reduce 将报错。
  • 返回值:函数累计处理的结果
[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr ); // 10

var sum = [{x: 1}, {x:2}, {x:3}].reduce(function (accumulator, currentValue) {
    return accumulator + currentValue.x;
},0)
console.log(sum) //  6

var flattened = [[0, 1], [2, 3], [4, 5]].reduce( function(a, b) {  return a.concat(b); }, []);// flattened is [0, 1, 2, 3, 4, 5]

//计算数组中每个元素出现的次数
var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
var countedNames = names.reduce(function (allNames, name) {
  if (name in allNames) {  
    allNames[name]++;  
  }  else {
    allNames[name] = 1;
  }
  return allNames;
}, {});
// countedNames is: { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }

//按属性对object分类
var people = [
  { name: 'Alice', age: 21 },
  { name: 'Max', age: 20 },
  { name: 'Jane', age: 20 }
];
function groupBy(objectArray, property) {
  return objectArray.reduce(function (acc, obj) {
    var key = obj[property];
    if (!acc[key]) {  acc[key] = [];    }
    acc[key].push(obj);
    return acc;
  }, {});
}
var groupedPeople = groupBy(people, 'age');
// groupedPeople is:
// {
//   20: [{ name: 'Max', age: 20 },{ name: 'Jane', age: 20 }],
//   21: [{ name: 'Alice', age: 21 }]
// }
reduceRight

从右到左为每个数组元素执行一次回调函数,并把上次回调函数的返回值放在一个暂存器中传给下次回调函数,并返回最后一次回调函数的返回值

  • 同reduce相似:只是从右到左遍历数组
  • 数组内>1个元素
    • 提供initialValue:accumulator为initialValue,currentValue为最后一个元素
    • 未提供 initialValue:accumulator为数组中最后一个元素
      currentValue 为倒数第二个元素
  • 数组内1个元素,未提供 initialValue,直接返回数组中的唯一一个元素
  • 数组内0个元素
    • 提供initialValue,直接返回 initialValue
    • 未提供initialValue,抛出 TypeError 错误
[0, 1, 2, 3, 4].reduceRight(function(previousValue, currentValue, index, array) {
    return previousValue + currentValue;
});

var flattened = [[0, 1], [2, 3], [4, 5]].reduceRight(function(a, b) {
    return a.concat(b);
}, []);// flattened is [4, 5, 2, 3, 0, 1]
values

返回一个数组迭代器对象,该迭代器会包含所有数组元素的值

  • arr.values()
    • 返回值:一个新的 Array 迭代对象。
//使用 for...of 循环进行迭代
let arr = ['w', 'y', 'k', 'o', 'p'];
let eArr = arr.values();

for (let letter of eArr) {
  console.log(letter);
} //"w" "y "k" "o" "p"
keys

返回一个数组迭代器对象,该迭代器会包含所有数组元素的键

  • arr.keys()

    • 返回值 :一个新的 Array 迭代器对象。
    
    var arr = ["a", , "c"];
    var sparseKeys = Object.keys(arr);
    var denseKeys = [...arr.keys()];
    console.log(sparseKeys); // ['0', '2']
    console.log(denseKeys);  // [0, 1, 2]
    //索引迭代器会包含那些没有对应元素的索引
    
entries

返回一个数组迭代器对象,该迭代器会包含所有数组元素的键值对

  • arr.entries()
    • iterator.next():遍历迭代器取得原数组的[key,value]
      • 返回一个对象,对于有元素的数组,// 是next{ value: Array(2), done: false }
  • 返回值:一个新的 Array 迭代器对象
const array1 = ['a', 'b', 'c'];
const iterator1 = array1.entries();

for (let e of iterator) {
    console.log(e);
}
// [0, "a"]
// [1, "b"]
// [2, "c"]

console.log(iterator1.next().value);//{value: Array(2), done: false}
/*
    done: false
    value: Array(2)
    0: 0
    1: "a"
    length: 2
*/
console.log(iterator1.next().value);//{value: Array(2), done: false}
/*
    done: false
    value: Array(2)
    0: 1
    1: "b"
    length: 2
*/
console.log(iterator1.next().value);//{value: Array(2), done: false}
/*
    done: false
    value: Array(2)
    0: 2
    1: "c"
    length: 2
*/
console.log(iterator1.next().value); //{value: undefined, done: true}
/*
    done: true
    value: undefined
*/
  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值