zoukankan      html  css  js  c++  java
  • 读阮一峰ES6笔记2:变量的解构赋值

    1、数组的解构赋值

    基本用法

    ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

    以前,为变量赋值,只能直接指定值。

    let a = 1;
    let b = 2;
    let c = 3;

    ES6 允许写成下面这样。

    let [a, b, c] = [1, 2, 3];

    本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。

    下面是一些使用嵌套数组进行解构的例子。

    let [ , , third] = ["foo", "bar", "baz"];
    third // "baz"
    
    let [x, , y] = [1, 2, 3];
    x // 1
    y // 3
    
    let [head, ...tail] = [1, 2, 3, 4];
    head // 1
    tail // [2, 3, 4]
    
    let [x, y, ...z] = ['a']; //如果解构不成功,变量的值就等于undefined
    x // "a"
    y // undefined
    z // []
    let [a, [b], d] = [1, [2, 3], 4]; //另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。
    a // 1
    b // 2
    d // 4

    如果等号的右边不是数组(或者严格地说,不是可遍历的结构,参见《Iterator》一章),那么将会报错。

    // 报错
    let [foo] = 1;
    let [foo] = false;
    let [foo] = NaN;
    let [foo] = undefined;
    let [foo] = null;
    let [foo] = {};

    对于 Set 结构,也可以使用数组的解构赋值。

    let [x, y, z] = new Set(['a', 'b', 'c']);  //ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。(梁涛注)
    x // "a"

    事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。

    function* fibs() { //fibs是一个 Generator(生成器)函数
      let a = 0;
      let b = 1;
      while (true) {
        yield a;           //执行到 yield 就停下来,并将yield 后边表达式的值 a,作为返回对象的 value 属性值,所有first=0 (梁涛注)
        [a, b] = [b, a + b]; //a=b  b=a+b 第一遍 a=1,b=1 第二遍 a=1 b=2 第三遍 a=2 b=3 第四遍 a=3 b=5 第五遍 a=5 b=8 第六遍 a=8 b=13                         
      }
    }
    
    let [first, second, third, fourth, fifth, sixth] = fibs();
    console.log(first);//0
    返回的a是未赋值前的值,所以first=0 second=1 third=1 fourth=2 fifth=3 sixth=5
    Generator函数的一般用法 (梁涛注)
    let f=fibs();
    console.log(f.next());//{value: 0, done: false}
    console.log(f.next());//{value: 1, done: false}
    console.log(f.next());//{value: 1, done: false}
    console.log(f.next());//{value: 2, done: false}

    默认值

    解构赋值允许指定默认值。

    let [foo = true] = [];
    foo // true
    
    let [x, y = 'b'] = ['a']; // x='a', y='b'
    let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'

    注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。

    let [x = 1] = [undefined];
    x // 1
    
    let [x = 1] = [null];   //null===undefined false
    x // null

    默认值可以引用解构赋值的其他变量,但该变量必须已经声明。

    let [x = 1, y = x] = [];     // x=1; y=1  x默认值生效,x=1   y默认值生效 y=x=1 (梁涛注)
    let [x = 1, y = x] = [2];    // x=2; y=2  x默认值不生效 x=2  y默认值生效 y=x=2
    let [x = 1, y = x] = [1, 2]; // x=1; y=2  x默认值不生效 x=1  y默认值不生效y=2
    let [x = y, y = 1] = [];     // ReferenceError: y is not defined x默认值生效,但y未声明。抛出异常

    2、对象的解构赋值 

    简介

    解构不仅可以用于数组,还可以用于对象。

    let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
    foo // "aaa"
    bar // "bbb"

    对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

    let { baz } = { foo: 'aaa', bar: 'bbb' };
    baz // undefined

    对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。

    // 例一
    let { log, sin, cos } = Math; //Math {abs: ƒ, acos: ƒ, acosh: ƒ, asin: ƒ, asinh: ƒ, …}将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上
    
    // 例二
    const { log } = console;
    console.log(console);//
    console {debug: ƒ, error: ƒ, info: ƒ, log: ƒ, warn: ƒ, …} (梁涛注) const {log} 即把console.log赋给log
    log(
    'hello') // hello

    对象的解构赋值是下面形式的简写

    let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };
    let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
    baz // "aaa"
    foo // error: foo is not defined

    默认值

    对象的解构也可以指定默认值。

    var {x = 3} = {};
    x // 3
    
    var {x, y = 5} = {x: 1};
    x // 1
    y // 5
    
    var {x: y = 3} = {};
    y // 3
    
    var {x: y = 3} = {x: 5};
    y // 5
    
    var { message: msg = 'Something went wrong' } = {};
    msg // "Something went wrong"

    默认值生效的条件是,对象的属性值严格等于undefined

    注意点

    (1)如果要将一个已经声明的变量用于解构赋值,必须非常小心。

    // 错误的写法
    let x;
    {x} = {x: 1};
    // SyntaxError: syntax error 
    // 正确的写法
    let x;
    ({x} = {x: 1});
     JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。

    (2)由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。
    let arr = [1, 2, 3];
    let {0 : first, [arr.length - 1] : last} = arr;
    first // 1
    last // 3

    上面代码对数组进行对象解构。数组arr0键对应的值是1[arr.length - 1]就是2键,对应的值是3。方括号这种写法,属于“属性名表达式”

    3、字符串的解构赋值

    字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
    const [a, b, c, d, e] = 'hello';
    a // "h"
    b // "e"
    c // "l"
    d // "l"
    e // "o"

    类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。

    let {length : len} = 'hello';
    len // 5

    4、函数参数的解构赋值

    函数的参数也可以使用解构赋值。

    function add([x, y]){
      return x + y;
    }
    
    add([1, 2]); // 3

    函数参数的解构也可以使用默认值。

    function move({x = 0, y = 0} = {}) {
      return [x, y];
    }
    
    move({x: 3, y: 8}); // [3, 8]
    move({x: 3}); // [3, 0]
    move({}); // [0, 0]
    move(); // [0, 0]

    函数move的参数是一个对象,通过对这个对象进行解构,得到变量xy的值。如果解构失败,xy等于默认值。

    注意,下面的写法会得到不一样的结果。
    function move({x, y} = { x: 0, y: 0 }) {
      return [x, y];
    }
    
    move({x: 3, y: 8}); // [3, 8]
    move({x: 3}); // [3, undefined]
    move({}); // [undefined, undefined]
    move(); // [0, 0]

    上面代码是为函数move的参数指定默认值,而不是为变量xy指定默认值,所以会得到与前一种写法不同的结果。

    5、圆括号问题

    建议只要有可能,就不要在模式中放置圆括号。

    可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。

    [(b)] = [3]; // 正确
    ({ p: (d) } = {}); // 正确
    [(parseInt.prop)] = [3]; // 正确

    6、用途

    变量的解构赋值用途很多。

    (1)交换变量的值

    let x = 1;
    let y = 2;
    
    [x, y] = [y, x];

    (2)从函数返回多个值

    函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。

    // 返回一个数组
    function example() {
      return [1, 2, 3];
    }
    let [a, b, c] = example();
    
    // 返回一个对象
    function example() {
      return {
        foo: 1,
        bar: 2
      };
    }
    let { foo, bar } = example();

    (3)函数参数的定义

    解构赋值可以方便地将一组参数与变量名对应起来。

    // 参数是一组有次序的值
    function f([x, y, z]) { ... }
    f([1, 2, 3]);
    
    // 参数是一组无次序的值
    function f({x, y, z}) { ... }
    f({z: 3, y: 2, x: 1});

    (4)提取 JSON 数据

    解构赋值对提取 JSON 对象中的数据,尤其有用。

    let jsonData = {
      id: 42,
      status: "OK",
      data: [867, 5309]
    };
    
    let { id, status, data: number } = jsonData;
    
    console.log(id, status, number);
    // 42, "OK", [867, 5309]

    (5)函数参数的默认值

    jQuery.ajax = function (url, {
      async = true,
      beforeSend = function () {},
      cache = true,
      complete = function () {},
      crossDomain = false,
      global = true,
      // ... more config
    } = {}) {
      // ... do stuff
    };

    指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || 'default foo';这样的语句。

    6)遍历 Map 结构

    任何部署了 Iterator 接口的对象,都可以用for...of循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。

    const map = new Map();
    map.set('first', 'hello');
    map.set('second', 'world');
    
    for (let [key, value] of map) {
      console.log(key + " is " + value);
    }
    // first is hello
    // second is world

    (7)输入模块的指定方法

    加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。

    const { SourceMapConsumer, SourceNode } = require("source-map");
    原文地址
  • 相关阅读:
    查看端口有没有被占用
    微信公众号2()
    How to insert a segment of noise to music file
    puppet practice
    Docker Commands
    LempelZiv algorithm realization
    The algorithm of entropy realization
    Java network programmingguessing game
    Deploy Openstack with RDO and Change VNC console to Spice
    puppet overview
  • 原文地址:https://www.cnblogs.com/liangtao999/p/11735480.html
Copyright © 2011-2022 走看看