发布于

块级作用域绑定及解构

Authors
  • avatar
    Name
    田中原
    Twitter

块级作用域绑定

块级声明

  • const和let只在当前代码块内有效,一旦执行到块外会立即被销毁。

  • javascript中的常量如果是对象,则对象中的值可以修改。

    const name = 'lg'
    name = 'lee' // Uncaught TypeError: Assignment to constant variable.
    
    const person = { name: 'lg' }
    person.name = 'lee' // ok
    
  • javascript引擎在扫描代码发现变量声明时,要么将它们提升至作用域顶部(遇到var声明),要么将声明放到TDZ临时死区中(遇到let和const声明)

    if (true) {
      console.log(typeof a) // Uncaught ReferenceError: a is not defined
      let a = 1
    }
    

循环中的块级作用域绑定

  • for-in或for-of循环中使用const时的行为与使用let一致

    // 报错 Uncaught TypeError: Assignment to constant variable.
    for (const i = 0; i < 10; i++) console.log(i)
    // 正常输出 a b
    for (const item of ['a', 'b']) console.log(item)
    // 正常输出 a b
    for (const item in { a: 1, b: 2 }) console.log(item)
    

    在for-in和for-of循环中,因为每次迭代不会(像for循环的例子一样)修改已有绑定,而是会创建一个新绑定。

默认使用const,只有确实需要改变变量的值时使用let。这样可以在某种程度上实现代码的不可变,从而防止某些错误的产生。

解构:使数据访问更便捷

对象解构

  • 解构赋值

    const node = { a: 1, b: 2 }
    let { a, b } = node
    
    // 对已经声明的变量赋值
    const node = { a: 1, b: 2 }
    let a, b
    ;({ a, b } = node)
    

    一定要用一对小括号包裹解构赋值语句,javascript引擎将一对开放的花括号视为一个代码块,而语法规定,代码块语句不允许出现在赋值语句左侧,添加小括号后可以将块语句转化为一个表达式,从而实现整个解构赋值的过程。

  • 深层解构

    const obj = { a: { b: 1 } }
    let {
      a: { b },
    } = obj
    console.log(a) // a is not defined
    console.log(b) // 1
    
  • 默认值

    如果指定的局部变量名称在对象中不存在,那么这个局部变量会被赋值为undefined。

    const node = { a: 1, b: 2 }
    let { a, b, c } = node
    // 可以使用默认值
    let { a, b, c = 3 } = node
    

    注意: 如果值为null,不会执行默认值,只有为undefined才会走默认值

    const node = { a: 1, b: 2, c: null, d: undefined }
    let { a, b, c = 3, d = 4 } = node
    console.log(c, d) // null 4
    
  • 为非同名局部变量赋值

    const node = { a: 1, b: 2 }
    let { a: A, b: B } = node
    console.log(A, B) // 1 2
    

    所有冒号前的标识符都代表在对象中的检索位置,其右侧为被赋值的变量名。

    示例:将一个对象的部分属性赋值给另外一个对象

    let obj1 = { a: 1, b: 1 }
    let obj2 = { a: 2, b: 2 }(({ a: obj2.a } = obj1)) // Invalid destructuring assignment target
    

数组解构

通过在数组中的位置进行选取,且可以将其存储在任意变量中,未“显式声明”的元素都会被直接被忽略。

let colors = ['red', 'blue', 'green']
let [, , thirdColor] = colors
console.log(thirdColor)

// 对已声明的变量进行赋值
let colors = ['red', 'blue', 'green']
let thirdColor
;[, , thirdColor] = colors

注意:不需要小括号包裹表达式,这一点与对象解构的约定不同

不定元素

let colors = ['red', 'blue', 'green']
let [firstColor, ...otherColor] = colors
console.log(otherColor) // ["blue", "green"]

...语法将数组中的其余元素赋值给一个待定的变量。

示例:克隆数组

let colors = ['red', 'blue', 'green'];
// es5方式
colors.concat()
// es6方式
[...colors]

注意:在被解构的数组中,不定元素必须为最后一个条目!

解构参数

function test(a, { b, c }) {
  console.log(a, b, c)
}
test(1, { b: 2, c: 3 }) // 1 2 3
test(4) // Uncaught TypeError: Cannot destructure property `b` of 'undefined' or 'null'.

注意:解构参数,调用函数不提供被解构的参数会导致程序抛出错误。let {b, c} = undefined;

处理方式,让上述参数可选!

function test(a, { b, c } = {}) {
  console.log(a, b, c)
}
test(1, { b: 2, c: 3 }) // 1 2 3
test(4) // 4 undefined undefined