美文网首页
ES6数组的扩展

ES6数组的扩展

作者: 那谁与我无关a | 来源:发表于2018-12-03 16:47 被阅读0次

    最近一直在看es6新曾的一写数组的拓展,总结出了一些知识点

    • find,findIndex,inclueds
    • Map Set
    • 静态方法(from,of)

    find,findIndex,inclueds

    find和findIndex

    语法

    arr .find(callback(element[, index[, array]])[, thisArg])
    arr .findIndex(callback(element[, index[, array]])[, thisArg])

    参数

    callback

    函数对数组中的每个值执行,取三个参数

    element

    当前元素在数组中处理。

    index(可选的)

    数组中正在处理的当前元素的索引。

    array(可选的)

    该阵列find被召唤。

    thisArg (可选的)

    this在执行时使用的对象callback。

    数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员的value。如果没有符合条件的成员,则返回undefined。

    let 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 }
    

    下面代码是找出数组中第一个大于9的成员

    [1, 5, 10, 15].find((value, index, arr)=> {
      return value > 9;
    }) // 10
    
    [1, 5, 10, 15].find((value, index, arr)=> {
      if(index>2){
        return value > 9;
      }
    }) // 15
    

    数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。上面find一样,不赘述。

    [1, 5, 10, 15].findIndex(function(value, index, arr) {
      return value > 9;
    }) // 2
    

    这两个方法都可以接受第二个参数,用来绑定回调函数的this对象。

    function f(value){
      return value > this.age;
    }
    let person = {name: 'John', age: 20};
    [10, 12, 26, 15].find(f, person);    // 26
    

    includes

    includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似

    语法

    arr .includes(searchElement [,fromIndex])

    参数

    searchElement

    要在数组中定位的元素。

    fromIndex (可选的)

    用于开始搜索的索引。如果索引大于或等于数组的长度,则返回-1,这意味着不会搜索该数组。如果提供的索引值为负数,则将其作为数组末尾的偏移量。注意:如果提供的索引为负数,则仍会从前到后搜索数组。如果提供的索引为0,则将搜索整个数组。默认值:0(搜索整个数组)。

    返回值

    数组中元素的第一个索引; -1如果没有找到。

    [1, 2, 3].includes(2)     // true
    [1, 2, 3].includes(4)     // false
    [1, 2, NaN].includes(NaN) // true
    
    [1, 2, 3].includes(3, 3);  // false
    [1, 2, 3].includes(3, -1); // true
    

    没有该方法之前,我们通常使用数组的indexOf方法,检查是否包含某个值。
    indexOf方法有两个缺点,一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于-1,表达起来不够直观。二是,它内部使用严格相等运算符(===)进行判断,这会导致对NaN的误判。
    includes使用的是不一样的判断算法,就没有这个问题。

    [NaN].indexOf(NaN)
    // -1
    [NaN].includes(NaN)
    // true
    

    另外,这find(),findIndex()两个方法都可以发现NaN,也弥补了数组的indexOf方法的不足。

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

    附: Object.is() , === 和 == 对比表


    对比表
    //Object.is()的实现原理
    isObject = function(x, y) {
        if (x === y) { // Steps 1-5, 7-10
          // 针对 +0不等于-0
          return x !== 0 || 1 / x === 1 / y;
        } else {
          // 针对 NaN等于NaN
          return x !== x && y !== y;
        }
      };
    

    数组的去重

    //最原始方法
    var array = [1, 1, '1', '1'];
    
    function unique(array) {
        // res用来存储结果
        var res = [];
        for (var i = 0, arrayLen = array.length; i < arrayLen; i++) {
            for (var j = 0, resLen = res.length; j < resLen; j++ ) {
                if (array[i] === res[j]) {
                    break;
                }
            }
            // 如果array[i]是唯一的,那么执行完循环,j等于resLen
            if (j === resLen) {
                res.push(array[i])
            }
        }
        return res;
    }
    
    console.log(unique(array)); // [1, "1"]
    
    
    //indexOf
    var array = [1, 1, '1'];
    
    function unique(array) {
        var res = [];
        for (var i = 0, len = array.length; i < len; i++) {
            var current = array[i];
            if (res.indexOf(current) === -1) {
                res.push(current)
            }
        }
        return res;
    }
    
    console.log(unique(array));
    
    //filter
    var array = [1, 2, 1, 1, '1'];
    
    function unique(array) {
        var res = array.filter(function(item, index, array){
            return array.indexOf(item) === index;
        })
        return res;
    }
    
    console.log(unique(array));
    

    Map和Set

    在以数组和对象为编程主力的JavaScript 语言,ES6 中引入了4种新的数据结构,分别是:集合(Set)、弱集合(WeakSet)、映射(Map)、弱映射(WeakMap)。

    Set

    Set 对象是值的集合,可以按照插入的顺序迭代它的元素。Set 中的元素只会出现一次,即 Set 中的元素是唯一的。

    语法

    new Set([ iterable ]);

    参数

    iterable
    是一个可迭代的对象,它的所有元素将被添加到新的 Set 中。
    由于 Set 中的值总是唯一的,所以需要判断两个值是否相等。在上面,内部使用Object.is()方法检测两个值是否一致,但+0、-0和0被视为是相等的元素,NaN 和 undefined 是可以被存储在 Set 中的,因为 NaN 在ES6中是严格相等的。

    new Set([NaN, NaN, 2, "2", +0, -0]); // Set(4) {NaN, 2, '2', 0}
    

    属性

    Set.prototype.size:返回 Set 对象的值的个数。

    let mySet1 = new Set([NaN, NaN, 2, 3, 5, 5]);
    mySet1.size; // 4
    

    方法

    (1)、在 Set 对象尾部添加一个元素:Set.prototype.add(value)

    let  mySet1=new Set([NaN,1,2,3]).add(NaN).add(2).add(4); //Set(5) {NaN, 1, 2, 3, 4}
    

    (2)、清除 Set 中所有的元素:Set.prototype.clear()

    let mySet2=new Set(NaN,1,2,3).clear();  //undefined
    

    (3)、判断值是否存在于 Set 中:Set.prototype.has(value);

    let mySet3=new Set([1,2,3,4,5]).has(2); //true
    let mySet4=new Set([1,2,3,4,5]).has(7); //false
    

    (4)、删除 Set 中的某个值: Set.prototype.delete(value);

    var mySet = new Set();
    mySet.add("foo");
    mySet.delete("bar"); // 返回 false,不包含 "bar" 这个元素
    mySet.delete("foo"); // 返回 true,删除成功
    mySet.has("foo");    // 返回 false,"bar" 已经成功删除
    

    WeakSet

    1、WeakSet 结构与 Set 结构类似,WeakSet 是一个构造函数,可以使用 new 命令创建 WeakSet 数据结构。

    const a= ["yuan", "monkey"];
    const myWeakSet = new WeakSet(a);  // WeakSet {"yuan", "monkey" }
    

    2、与 Set 区别
    (1)、WeakSet 的成员只能是对象,而不能是其他类型的值。
    (2)、WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用。 也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。这是因为垃圾回收机制依赖引用计数,如果一个值的引用次数不为0,垃圾回收机制就不会释放这块内存。结束使用该值之后,有时会忘记取消引用,导致内存无法释放,进而可能会引发内存泄漏。WeakSet 里面的引用,都不计入垃圾回收机制,所以就不存在这个问题。因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。

    由于上面这个特点,WeakSet 的成员是不适合引用的,因为它会随时消失。另外,由于 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历。

    这些特点同样适用于本章后面要介绍的 WeakMap 结构。
    (3)、WeakSet 没有size 属性,没有办法遍历其成员。
    3、方法
    (1)、WeakSet.prototype.add(value):添加新成员;
    (2)、WeakSet.prototype.delete(value):清楚指定成员;
    (3)、WeakSet.prototype.has(value):判断是否存在某个成员

    Map

    Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
    一个Map对象以插入顺序迭代其元素 — 一个 for...of 循环为每次迭代返回一个[key,value]数组。

    语法

    new Map([ iterable ]);

    参数

    iterable
    Iterable 可以是一个数组或者其他 iterable 对象,其元素或为键值对,或为两个元素的数组。 每个键值对都会添加到新的 Map。null 会被当做 undefined。

    方法

    (1)Map.prototype.set(key, value)
    设置Map对象中键的值。返回该Map对象。
    (2)Map.prototype.clear()
    移除Map对象的所有键/值对 。
    (3)Map.prototype.has(key)
    返回一个布尔值,表示Map实例是否包含键对应的值。

    myMap.set("bar", "baz");
    myMap.set(1, "foo");
    
    myMap.size;       // 2
    myMap.has("bar"); // true
    
    myMap.clear();
    
    myMap.size;       // 0
    myMap.has("bar")  // false
    

    (4)Map.prototype.delete(key)
    移除任何与键相关联的值,并且返回该值,该值在之前会被

    var myMap = new Map();
    myMap.set("bar", "foo");
    myMap.delete("bar"); // 返回 true。成功地移除元素
    myMap.has("bar");    // 返回 false。"bar" 元素将不再存在于 Map 实例中
    

    应用

    应用
    (1)、Map 与 数组之间的相互转换

    // Map 转数组
    var myMap = new Map();
    myMap.set("bar", "foo");
    myMap.set(1, "bar");
    [...myMap]; //  [ ["bar", "foo"], [1, "bar"] ]
    // 数组转Map
    const arr = new Map( [ ["bar", "foo"], [1, "bar"] ]);
    console.log(arr);  // Map {"bar" => "foo", 1 => "bar"}
    

    (2)、Map 与对象相互转换

    // Map 转对象
    function strMapToObj(strMap) {
      let obj = Object.create(null);
      for (let [k, v] of strMap) {
        obj[k] = v;
      }
      return obj;
    }
     const myMap = new Map();
    myMap.set("bar", "foo")
    .set(1, "ooo");
    
    strMapToObj(myMap ); // Object {1: "ooo", bar: "foo"}
    
    // 对象转 Map
    function objToStrMap(obj) {
      let strMap = new Map();
      for (let k of Object.keys(obj)) {
        strMap.set(k, obj[k]);
      }
      return strMap;
    }
    objToStrMap({1: "ooo", bar: "foo"}); // Map {"1" => "ooo", "bar" => "foo"}
    

    (3)、Map 与 JSON 相互转换

    // Map 转 JSON
    // Map 的键名为字符串
    function strMapToJson(jsonStr) {
      return JSON.stringify(strMapToObj(jsonStr));
    }
    const myMap = new Map();
    myMap.set("bar", "foo")
    .set(1, "ooo");
    strMapToJson(myMap); // "{"1":"ooo","bar":"foo"}"
    
    // Map 的键名为非字符串
    function mapToArrayJson(map) {
      return JSON.stringify([...map]);
    }
    mapToArrayJson(myMap); // "[["bar","foo"],[1,"ooo"]]"
    
    // Json 转 Map
    // 正常情况下所有键名都为字符串
    function jsonToStrMap(jsonStr) {
      return objToStrMap(JSON.parse(jsonStr));
    }
    jsonToStrMap("{"1":"ooo","bar":"foo"}"); // Map {"1" => "ooo", "bar" => "foo"}
    
    // 整个JSON 是数组
    function jsonToMap(jsronStr) {
      return new Map(JSON.parse(jsronStr)); 
    }
    jsonToMap([["bar","foo"],[1,"ooo"]]); // Map {"1" => "ooo", "bar" => "foo"}
    

    WeakMap

    含义

    WeakMap 结构与 Map结构类似,也是用于生成键值对的集合。

    与 Map 区别

    (1)WeakMap 只接受对象作为键名(null 除外),不接受其他类型的值作为键名。
    (2)WeakMap 的键名所指向的对象不计入垃圾回收机制。
    (3)没有keys()、values()、entries() 遍历操作。
    (4)没有size 属性。
    (5)不支持clear() 方法。
    WeakMap 应用的典型场合就是 DOM 节点作为键名。下面是一个例子。

    let myElement = document.getElementById('logo');
    let myWeakmap = new WeakMap();
    
    myWeakmap.set(myElement, {timesClicked: 0});
    
    myElement.addEventListener('click', function() {
      let logoData = myWeakmap.get(myElement);
      logoData.timesClicked++;
    }, false);
    

    上面代码中,myElement是一个 DOM 节点,每当发生click事件,就更新一下状态。我们将这个状态作为键值放在 WeakMap 里,对应的键名就是myElement。一旦这个 DOM 节点删除,该状态就会自动消失,不存在内存泄漏风险。

    静态方法(from,of)

    Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。

    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']
    
    //Set
    let newArray=new Set(['a','b','c'])
    let arr3=Array.from(newArray) //['a','b','c']
    
    

    Array.to方法是用于将一组值,转换为数组。和Array()的用途相似,但是这个方法的主要目的,是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。

    Array() // []
    Array(3) // [, , ,]
    Array(3, 11, 8) // [3, 11, 8]
    
    Array.of() // []
    Array.of(1) // [1]
    Array.of(3,11,8) // [1, 2]
    

    上面代码中,Array方法没有参数、一个参数、三个参数时,返回结果都不一样。只有当参数个数不少于 2 个时,Array()才会返回由参数组成的新数组。参数个数只有一个时,实际上是指定数组的长度。
    Array.of基本上可以用来替代Array()或new Array(),并且不存在由于参数不同而导致的重载。它的行为非常统一。Array.of总是返回参数值组成的数组。如果没有参数,就返回一个空数组。

    数组的空值

    数组的空位指,数组的某一个位置没有任何值。比如,Array构造函数返回的数组都是空位。注意,空位不是undefined,一个位置的值等于undefined,依然是有值的。空位是没有任何值

    ES5 对空位的处理,已经很不一致了,大多数情况下会忽略空位。

    forEach(), filter(), reduce(), every() 和some()都会跳过空位。
    map()会跳过空位,但会保留这个值
    join()和toString()会将空位视为undefined,而undefined和null会被处理成空字符串。

    // forEach方法
    [,'a'].forEach((x,i) => console.log(i)); // 1
    
    // filter方法
    ['a',,'b'].filter(x => true) // ['a','b']
    
    // every方法
    [,'a'].every(x => x==='a') // true
    
    // reduce方法
    [1,,2].reduce((x,y) => x+y) // 3
    
    // some方法
    [,'a'].some(x => x !== 'a') // false
    
    // map方法
    [,'a'].map(x => 1) // [,1]
    
    // join方法
    [,'a',undefined,null].join('#') // "#a##"
    
    // toString方法
    [,'a',undefined,null].toString() // ",a,,"
    

    ES6中则是明确的将空处理成了undefined,由于空位的处理规则非常不统一,所以建议避免出现空位。
    Array.from方法会将数组的空位,转为undefined,也就是说,这个方法不会忽略空位。

    Array.from(['a',,'b'])
    // [ "a", undefined, "b" ]
    
    扩展运算符(...)也会将空位转为undefined。
    
    [...['a',,'b']]
    // [ "a", undefined, "b" ]
    copyWithin()会连空位一起拷贝。
    
    [,'a','b',,].copyWithin(2,0) // [,"a",,"a"]
    fill()会将空位视为正常的数组位置。
    
    new Array(3).fill('a') // ["a","a","a"]
    for...of循环也会遍历空位。
    
    let arr = [, ,];
    for (let i of arr) {
      console.log(1);
    }
    // 1
    // 1
    

    问题 :
    1.不太了解静态方法和实例方法的区别
    2.对promise概念有点模糊,async 的使用

    相关文章

      网友评论

          本文标题:ES6数组的扩展

          本文链接:https://www.haomeiwen.com/subject/fxpgqqtx.html