美文网首页
12- ES6 扩展运算符

12- ES6 扩展运算符

作者: 夏海峰 | 来源:发表于2018-08-21 16:59 被阅读12次

    1、扩展运算符

    扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。

    function push(array, ...items) {
        array.push(...items);
    }
    
    console.log(...[1,2,3]);
    console.log(1, ...[2,3,4], 5);
    
    [...document.querySelectorAll('div')];
    // [<div>, <div>, <div>]
    

    扩展运算符主要用于函数调用

    const nums = [2,4];
    add(...nums);  // 等同于 add(2,4);
    

    扩展运算符与正常的函数参数可以结合使用,非常灵活。

    const args = [0, 1];
    f(-1, ...args, 3,4, ...[6]);
    

    扩展运算符后面还可以放置表达式。

    const arr = [...(x > 0 ? ['a'] : ['b']), 'c', 'd'];
    [...[], 2];  // [2]
    

    2、替代函数的apply方法,some.func.apply(obj, [])

    // 例一
    function f(x,y,z) {};
    const args = [1,2,3];
    // ES5写法
    f.apply(null, [1,2,3]);
    // ES6写法
    f(...args);
    
    // 例二
    // ES5写法
    Math.max.apply(null, [23,5,78]);
    // ES6写法
    Math.max(...[23,5,78]);
    // 等同于
    Math.max(23,5,78);
    
    // 例三
    var arr1 = [1,2,3];
    var arr2 = [4,5,6];
    // ES5写法
    Array.prototype.push.apply(arr1, arr2);
    // ES6写法
    arr1.push(...arr2);
    
    // 例四
    // ES5写法
    new (Date.bind.apply(Date, [null, 2018, 4, 29]));
    // ES6写法
    new Date(...[2018, 4, 29]);
    

    3、扩展运算符的应用
    应用1:复制数组

    数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。

    const a1 = [1,2];
    const a2 = a1;
    a2[1] = 100;  // a2和a1指向同一个引用地址
    a1;   // [1, 100]
    
    // ES5写法
    const a2 = a1.concat();
    // ES6写法
    const a2 = [...a1];
    // 或者
    const [...a2] = a1;
    

    应用2:合并数组

    // ES5写法
    [1,2].concat([3,4]);
    [1,2].concat([3,4], [5,6]);
    
    // ES6写法
    [1,2,...[3,40]];
    [...[1,2], ...[3,4], ...[5,6]];
    

    应用3:与解构赋值结合

    const arr = [1,2,3,4,5];
    // ES5写法
    const a = arr[0];
    const rest = arr.slice(1);
    
    // ES6写法
    const [a, ...rest] = arr;
    // 如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。
    

    应用4:扩展运算符与字符串

    扩展运算符还可以将字符串转为真正的数组。

    [..."hello"];
    // ["h", "e", "l", "l", "o"]
    

    扩展运算符,能够正确识别四个字节的 Unicode 字符

    应用5:扩展运算符实现了 Iterator接口对象

    任何 Iterator 接口的对象,都可以用扩展运算符转为真正的数组。

    let nodeList = document.querySelectorAll('div');
    let array = [...nodeList];
    

    对于那些没有部署 Iterator 接口的类似数组的对象,扩展运算符就无法将其转为真正的数组。

    应用6:Map 和Set结构,Generator函数

    扩展运算符内部调用的是数据结构的 Iterator 接口,因此只要具有 Iterator 接口的对象,都可以使用扩展运算符,比如 Map 结构。

    let map = new Map([
        [1, 'a'],
        [2, 'b'],
        [3, 'c']
    ]);
    let arr = [...map.keys()];   // [1,2,3]
    

    Generator 函数运行后,返回一个遍历器对象,因此也可以使用扩展运算符。

    const go = function*() {
        yield 1;
        yield 2;
        yield 3;
    }
    [...go()];    // [1,2,3]
    

    对非Iterator 接口的对象使用扩展运算符,将会报错。

    4、对象的扩展运算符

    // 扩展运算符(...)
    const [a, ...b] = [1, 2, 3];
    b;  // [2, 3]
    
    let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
    z;  // { a: 3, b: 4 }
    

    解构赋值必须是最后一个参数,否则会报错。

    解构赋值的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么解构赋值拷贝的是这个值的引用,而不是这个值的副本。

    let obj = { a: { b: 1 } };
    let { ...x } = obj;
    obj.a.b = 100;
    x.a.b;  // 100
    

    对象的扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。这等同于使用Object.assign方法。

    let z = { a: 1, b: 2 };
    let n = { ...z };
    n;   // { a: 1, b: 2 }
    

    扩展运算符可以用于合并两个对象。

    let ab = { ...a, ...b };
    // 等同于
    let ab = Object.assign({}, a, b);
    

    如果用户自定义的属性,放在扩展运算符后面,则扩展运算符内部的同名属性会被覆盖掉。

    let obj = { ...a, x:1, y:2 };
    let obj = { ...a, ...{ x:1, y:2 } };
    let x=1, y=2, obj = { ...a, x, x };
    let obj = Object.assign({}, a, {x:1, y:2});
    

    与数组的扩展运算符一样,对象的扩展运算符后面可以跟表达式。

    const obj = {
        ...{x > 0 ? {a:1} : {b:2}},
        c: 3
    }
    

    扩展运算符(...)内部使用的是 for...of循环。


    完!!!

    相关文章

      网友评论

          本文标题:12- ES6 扩展运算符

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