zoukankan      html  css  js  c++  java
  • ES6 之 解构赋值

    本博文配合 阮一峰 《ES6 标准入门(第3版)》一书进行简要概述 ES6 中变量的解构赋值。 

    数组的解构赋值

    基本用法

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

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

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


    ES6 允许写成下面的样式。

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

    该代码表示,可以从数组中提取值,按照对应位置,对变量赋值。

    相关示例

    本质上来说,这种写法属于“模式匹配”。即只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。

    let [foo, [[bar], baz]] = [1, [[2], 3]]
    foo // 1
    bar // 2
    baz // 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']
    x // "a"
    y // undefined
    z // []


    如果解构不成功,变量的值就等于 undefined

    let [foo] = []
    foo //undefined
    let [bar, foo] = [1]
    foo //undefined

    以上两种情况都属于解构不成功,foo 的值都会等于undefined


    另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。

    let [x, y] = [1, 2, 3]
    x // 1
    y // 2
    
    let [a, [b], d] = [1, [2, 3], 4]
    a // 1
    b // 2
    d // 4

    以上两个例子,都属于不完全解构,但是可以成功。


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

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

    默认值

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

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



    查看数组对应对值有没有?如果没有(数组对没有指 undefined)就使用默认值,如果有就使用对应值。需要注意的是 undefined 和 null 的区别,一个是没有声明值,一个是值为 null

    let [a = 2, b = 3] = [undefined, null]
    a //2
    b //null

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



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

    let [x = 1, y = x] = []     // x=1; y=1
    let [x = 1, y = x] = [2]    // x=2; y=2
    let [x = 1, y = x] = [1, 2]  // x=1; y=2
    let [x = y, y = 1] = []     // ReferenceError: y is not defined

    最后一个表达式之所以会报错,是因为 x 用 y 做默认值时,y 还没有声明。

    对象的解构赋值

    解构还可以用于对象。

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

    由于 ES6 中对象键值对相同时可以略写成一个,所以上面的代码等同于:

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

    也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。



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

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

    上面代码的第一个例子,等号左边的两个变量的次序,与等号右边两个同名属性的次序不一致,但是对取值完全没有影响。第二个例子的变量没有对应的同名属性,导致取不到值,最后等于 undefined

    默认值

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

    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

    var {x = 3} = {x: undefined}
    x // 3
    
    var {x = 3} = {x: null}
    x // null

    上面代码中,属性 x 等于 null ,因为 null 与 undefined 不严格相等,所以是个有效的赋值,导致默认值3不会生效。即如果解构失败,变量的值等于undefined


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

    // 错误的写法
    let x
    {x} = {x: 1}
    // SyntaxError: syntax error

    上面代码的写法会报错,因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。

    // 正确的写法
    let x
    ({x} = {x: 1})

    字符串的解构赋值

    字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

    const [a, b, c, d, e] = 'hello'
    a // "h"
    b // "e"
    c // "l"
    d // "l"
    e // "o"



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

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

    数值和布尔值的解构赋值

    解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。

    let {toString: s} = 123
    s === Number.prototype.toString // true
    
    let {toString: s} = true
    s === Boolean.prototype.toString // true

    上面代码中,数值和布尔值的包装对象都有 toString 属性,因此变量 s 都能取到值。

    解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于 undefined 和 null 无法转为对象,所以直接对它们进行解构赋值,都会报错。

    let { prop: x } = undefined  // TypeError
    let { prop: y } = null  // TypeError

    函数参数的解构赋值

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

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

    上面代码中,函数 add 的参数表面上是一个数组,但在传入参数的那一刻,数组参数就被解构成变量 x 和 y 。对于函数内部的代码来说,它们能感受到的参数就是 x 和 y

    另一个例子

    [[1, 2], [3, 4]].map(([a, b]) => a + b)
    // [ 3, 7 ]

    默认值

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

    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 的参数是一个对象,通过对这个对象进行解构,得到变量 x 和 y 的值。如果解构失败, x 和 y 等于默认值。

    解构赋值的作用

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

    交换变量的值

    交换变量 x 和 y 的值,这样的写法不仅简洁,而且易读,语义非常清晰。

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

    函数参数的定义

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

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

    提取 JSON 数据

    解构赋值对提取 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]
  • 相关阅读:
    把影响集中到一个点
    How to avoid Over-fitting using Regularization?
    适定性问题
    Numerical Differentiation 数值微分
    What Every Computer Scientist Should Know About Floating-Point Arithmetic
    Generally a good method to avoid this is to randomly shuffle the data prior to each epoch of training.
    What is the difference between iterations and epochs in Convolution neural networks?
    Every norm is a convex function
    Moore-Penrose Matrix Inverse 摩尔-彭若斯广义逆 埃尔米特矩阵 Hermitian matrix
    perl 类里的函数调用其他类的函数
  • 原文地址:https://www.cnblogs.com/evenyao/p/9689890.html
Copyright © 2011-2022 走看看