JavaScript集合引用类型之Array

  • 除了Object,Array就是ES中最常用的了。

  • ES数组跟其他编程语言的数组有很大区别:

    • ES数组自然也是一组有序的数据
    • ES数组中每一个槽位可以存储任意类型的数据
    • ES数组是动态大小的。
  • 创建数组的方式

    • new操作符 + Array构造函数 let colors = new Array();
        let colors = new Array(20); // length = 20
        let colors = new Array('red', 'blue', 'green'); // length = 3
      
    • 省略new操作符,结果和上面的结果一致。let aolors = Array(3);
    • 数组字面量array literal。let colors = []
    • 数组字面量表示法不会调用Array构造函数。
  • Array构造函数还有2个ES6新增的用于创建数组的静态方法:

    • from() : 用于将类数组结构转换为数组实例
    • of() :用于将一组参数转换为数组实例。
  • Array.from()第一个参数是一个类数组对象,即任何可迭代的结构,或者有一个length属性和可索引元素的结构。

    • 可迭代
    • 拥有length属性
    • 可索引元素
  // 字符串会被拆分为单字符数组
  Array.form('matt'); // ['m', 'a', 't', 't']

  // 可以使用from()将集合和映射转换为一个新数组
  const m = new Map().set(1, 2).set(3, 4);

  const 3 = new Set().add(1).add(2).add(3).add(4);

  Array.from(m); // [[1,2], [3,4]]
  Array.from(s); // [1,2,3,4]

  // Array.from对现有数组执行浅拷贝
  const a1 = [1, 2, 3, 4];
  const a2 = Array.from(a1);
  a1; // [1,2,3,4]
  a1 === a2 // false
  a1 == a2 // false

  // 可以使用任何可迭代对象
  const iter = {
    *[Symbol.iterator]() {
      yield 1;
      yield 2;
      yield 3;
      yield 4;
    }
  };
  Array.from(iter); // [1,2,3,4]

  // arguments对象可以被轻松地转换为数组
  function getArgsArray() {
    console.log(arguments); // [argumnets] {'0': 1, '1': 2, '2': 3, '3': 4}
    return Arrays.from(arguments)
  }
  getArgsArray(1,2,3,4); // [1,2,3,4]

  // from()也能转换带有必要属性的自定义对象
  const arrayLikeObject = {
    0: 1,
    1: 2,
    2: 3,
    3: 4,
    length: 4
  };
  Array.from(arrayLikeObject); // [1,2,3,4]
  • Array.from()还接收第二个可选的映射函数参数。该函数可以直接增强新数组的值,无需想调用Array.from().map()那样先创建一个中间数组。还可以接收第三个可选参数,用于指定映射函数中this的值。但这个重写的this值在箭头函数中不适用。

      const a1 = [1,2,3,4];
      const a2 = Array.from(a1, x => x**2); // a2 : [1, 4, 9, 16]
      const a3 = Array.from(a1, function(x) { return x ** this.exponent}, { exponent: 2}); // a3: [1, 4, 9, 16]
    
  • Array.of()可以把一组参数转换成数组。这个方法用于替代在ES6之前常用的Array.prototype.slice.call(arguments),一种笨拙的将arguments对象转换成数组的写法:

      Array.of(1,2,3,4); // [1,2,3,4]
      Array.of(undefined); // [undefined]
    
  • 数组空位

    • 使用数组字面量初始化数组时,可以使用一串逗号来创建空位hole。ES会将逗号之间相应索引位置的值当成空位,ES6规范重新定义了该如何处理这些空位。

    • ES6新增的方法和迭代器与早期ES版本中存在的方法行为不同。ES6新增方法普遍将这些空位当成存在的元素,只不过值为undefined。

      const a = Array.from([,,,]); 
      for(const val of a) {
        alert(val === undefined) ;
      }
      // true
      // true
      // true
      
      for(const [ index, value] of options.entries()) {
        alert(value);
      }
      // 1
      // 
      // 
      //
      // 5
    
  • 数组索引

    • 要取得或设置数组的值,需要使用中括号并提供相应值得数字索引。

    • 数组中元素得数量保存在length属性中,这个属性始终返回0或大于0的值。

    • 数组length属性只读且通过修改length属性来在数组尾增删元素。

    • 使用length属性可以方便地向数组尾添加元素。

    • 数组中最后一个元素的索引始终是length - 1,因此下一个新增槽位的索引就是length。

    • 数组最多可以包含4 294 967 295个元素。

  • 检测数组

    • 判断一个对象是不是数组:
      • 在只有一个网页(因而只有一个全局作用域)的情况下,使用instanceof操作符就可以了。
        if (value instanceof Array) {
          // 操作数组
        }
      
      • 一个全局执行上下文的情况下,可以使用instanceof操作符
      • 当涉及到网页里有多个框架时,可能设计不同的执行上下文时,ES提供了Array.isArray()方法
        if (Array.isArray(value)) {
          //操作数组
        }
      
  • 迭代器方法

    • ES6中,Array得原型上暴露了三个用于检索数组内容得方法:keys()、values()和entries()。
    • keys()返回数组索引得迭代器,values()返回数组的迭代器,而entries()返回索引/值对的迭代器。
      const a = ["foo", "bar", "baz", "qux"];
    
      // 因为这些方法都返回迭代器,所以可以使用Array.from()将之直接转换成数组实例
      const aKeys = Array.from(a.keys()); // [0, 1, 2, 3]
      const aValues = Array.from(a.values()); // ["foo", "bar", "baz", "qux"]
      const aEntries = Array.from(a.entries()); // [[0, "foo"], [1, "bar"], [2, "baz"], [3, "qux"]]
    
    • 使用ES6的结构可以非常容易地在循环中拆分键/值对:
      const a = ["foo", "bar", "baz", "qux"];
      for(const [idx, element] of a.entries()) {
        alert(idx);
        alert(element);
      }
      // 0
      // foo
      // 1
      // bar
      // 2
      // baz
      // 3
      // qux
    
    • 使用时要注意浏览器是否支持这些方法。
  • 复制和填充方法

    • ES6新增了两个方法:批量复制方法copyWithin()和填充数组方法fill()。

    • 这2个方法和函数签名类似,都需要指定既有数组实例上的一个范围,包含开始索引,不包含结束索引。使用找个方法不会改变数组的大小。

    • fill()方法可以向一个已有的数组中插入全局或部分相同的值。

      • 开始索引用于指定开始填充的位置,可选。若不提供结束索引,则一致填充到数组末尾。
      const zeroes = [0, 0, 0, 0, 0];
    
      // 用5填充
      zeroes.fill(5); // [5, 5, 5, 5, 5];
      zeroes.fill(0); // 重置
    
      // 用6填充索引大于等于3的元素
      zeroes.fill(6, 3); // [0,0,0,6,6]
      zeroes.fill(0);
      
      // 用7填充索引大于1且小于3的元素
      zeroes.fill(7, 1, 3); // [0, 7, 7, 0, 0]
      zeroes.fill(0);
    
      // 用8填充索引大于等于1且小于4的元素
      // (-4 + zeroes.length = 1)
      // (-1 + zeroes.length = 4)
      zeroes.fill(8, -4, -1); // [0, 8, 8, 8, 0]
    
      // *******************************
    
      // fill()静默忽略超出数组边界、零长度及方向相反的索引范围:
      const zeroes = [0,0,0,0,0];
    
      // 索引过低,忽略
      zeroes.fill(1, -10, -6); // [0,0,0,0,0]
    
      // 索引过高,忽略
      zeroes.fill(1, 10, 15)
    
      // 索引反向,忽略
      zeroes.fill(2, 4, 2)
    
      // 索引部分可用,填充可用部分
      zeroes.fill(4, 3, 10); // [0, 0, 0, 4, 4]
    
    • 与fill()不同,copyWithin()会按照指定范围浅拷贝数组中的部分内容,然后将它们插入到指定索引开始的位置。
    • 开始索引和结束索引则与fill()使用同样的计算方法:
      let ints, reset = () => ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
      reset();
    
      // 从ints中复制索引0开始的内容,插到索引5开始的位置
      // 在源索引或目标索引到达数组边界时停止
      ints.copyWithin(5); // [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
    
      // 从ints中复制索引5开始的内容,插入到索引0开始的位置
      ints.copyWithin(0, 5); // [5, 6, 7, 8, 9, 5, 6, 7, 8, 9]
    
      reset();
    
      // 从ints中复制索引0开始到索引3结束的内容
      // 插入到索引4开始的位置
      ints.copyWithin(4, 0, 3); // [0, 1, 2, 3, 0, 1, 2, 7, 8, 9]
      reset();
    
      // javascript引擎在插值前会完整复制范围内的值
      // 因此复制期间不存在重写的风险
      ints.copyWithin(2, 0, 6); // [0, 1, 0, 1, 2, 3, 4, 5, 8, 9]
    
      reset();
    
      // 支持负索引值,与fill()相对于数组末尾计算正向索引的过程是一样的
      // -4 + 10 = 6
      // -7 + 10 = 3
      // -3 + 10 = 7
      // 所以是从索引3复制到索引7,插到索引6开始
      ints.copyWithin(-4, -7, -3); // [0, 1, 2, 3, 4, 5, 3, 4, 5, 6]
    
      reset()
    
      // copyWithin()静默忽略超出数组边界、零长度及方向相反的索引范围:
    
      // 索引过低,忽略
      ints.copyWithin(1, -15, -12);
    
      // 索引过高,忽略
      ints.copyWithin(1, 12, 15);
    
      // 索引反向
      ints.copyWithin(2, 4, 2);
    
      // 索引部分可用,复制、填充可用部分
      ints.copyWithin(4, 7, 10); // [0, 1, 2, 3, 7, 8, 9, 7, 8, 9];
    
  • 转换方法

    • 所有对象都有toLocaleString()、toString()和valueOf()方法。
    • valueOf()返回的是数组本身
    • toString()返回由数组中每个值的等效字符串拼接而成的一个逗号分隔的字符串。
      let colors = [ 'red', 'blue', 'green' ];
      colors.toString(); // 'red,blue,green'
      colors.valueOf(); // ['red', 'blue', 'green']
    
    • toLocaleString()方法也可能返回跟toString()和valueOf()相同的结果,但也不一定。
      let person1 = {
        toLocaleString() {
          return 'Nikolaos';
        }
        toString() {
          return 'Nicholas';
        }
      }
    
      let person2 = {
        toLocaleString() {
          return 'Grigorios';
        }
        toString() {
          return 'Greg
        }
      }
    
      let person = [person1, person2];
      alert(person); // Nicholas,Greg
      alert(person.toString()); // Nicholas,Greg
      alert(person.toLocaleString()); // Nikolas,Grigorios
    
    • alert()期待的是参数是字符串类型,所以遇到不是字符串类型的数据会在后台调用toString()。

    • 继承的方法toLocaleString()以及toString()都返回数组值的逗号分隔的字符串。

    • 如果想用不同的分隔符,可以使用join()方法。

    • 若数组中某一项是null或undefined,则在join()、toLocaleString()、toString()和ValueOf()返回的结果中会以空字符串表示

  • 栈方法

    • ES给数组提供了几个方法,让它看起来像另外一种数据结构。

    • 数组对象可以像栈一样,也就是一种限制插入和删除项的数据结构。

    • 栈: 先进后出

    • 数据插入: push()

    • 数据删除: pop()

    • push(): 将数据新增到数组末尾。

    • pop(): 将数组末尾项删除

  • 队列方法

    • 先进先出,在队头获取数据,在队尾新增数据。
    • 在数组首(队头)获取数据shift()
    • 在数组尾(队尾)新增数据push()
  • 排序方法

    • 反序: reverse(),将数组逆转

    • 升序重新排列数组元素sort():最小值在前,最大值在后

    • sort()

      • sort()会在每一项上调用String()转型函数,然后比较字符串来决定顺序。即使数组的元素都是数值,也会先把数组转换为字符串再比较、排序。
        let values = [0, 1, 5, 10, 15];
        values.sort(); // 0, 1, 10, 15, 5
      
      • sort()会按照这些数值的字符串形式重新排序,因此会出现上述问题。
      • 因此,sort()方法还可用接收一个比较函数,用于判断哪个值应该排在前面。
      • 比较函数接收两个参数,如果第一个参数应该排在第二个参数前面,就返回负值;相等返回0;大于返回正值。
      • 简单的比较函数:
        function compare(value1, value2) {
          if (value1 < value2) {
            return -1;
          } else if (value1 > value2) {
            return 1;
          } else {
            return 0;
          }
        }
      
        let values = [0, 1, 5, 15, 10];
        values.sort(compare); // [0, 1, 5, 10, 15]
      
      • 比较函数也可以产生降序效果,只要把返回值交换一下就可以了
        function compare(value1, value2) {
          if (value1 < value2) {
            return 1;
          } else if (value1 > value2) {
            return -1;
          } else {
            return 0;
          }
        }
      
      • 比较函数也可以简写成箭头函数
        let values = [ 0, 1, 5, 10, 15];
        values.sort((a,b) => a < b ? 1 : a > b ? -1 : 0)
        alert(values); // 15,10,5,1,9
      
  • 操作方法

    • concat(),它首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组。
    • slice()
    • splice()
  • 搜索和位置方法

    • 按严格相等搜索
      • indexOf()
      • lastIndexOf()
      • includes()
    • 按断言函数搜索
    • 断言函数接收3个参数:元素、索引、数组本身
      • find()
      • findIndex()
  • 迭代方法

    • ES为数组定义了5个迭代方法。每个方法接收2个参数:以每一项为参数运行的函数,以及可选的作为函数运行上下文的作用域对象(影响函数中this的值)。
    • 函数接收三个参数:数组元素,元素索引和数组本身。
      • every()
      • filter()
      • forEach()
      • map()
      • some()
  • 归并方法

    • reduce()
    • reduceRight()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值