对象的结构赋值和拓展运算符

ES2015 引入了 Rest 参数和扩展运算符(...)。但是 ES2015 中的作用对象仅限于数组。

restParam(1, 2, 3, 4, 5)

function restParam(p1, p2, ...p3) {
  // p1 = 1
  // p2 = 2
  // p3 = [3, 4, 5]
}

const values = [99, 100, -1, 48, 16]
console.log(Math.max(...values)) // 100

ES2018 为对象解构提供了和数组一样的 Rest 参数和展开操作符。

const myObject = {
  a: 1,
  b: 2,
  c: 3,
}
const { a, ...x } = myObject
// a = 1
// x = { b: 2, c: 3 }

function foo({ a, ...param }) {
  console.log(a) // 1
  console.log(param) // {b: 2, c: 3}
}

由于解构赋值要求等号右边是一个对象,所以如果等号右边是 undefinednull,就会报错,因为它们无法转为对象。

let { ...z } = null // 运行时错误
let { ...z } = undefined // 运行时错误

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

let { ...x, y, z } = someObject; // 句法错误
let { x, ...y, ...z } = someObject; // 句法错误

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

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

上面代码中,x 是解构赋值所在的对象,拷贝了对象 obja 属性。a 属性引用了一个对象,修改这个对象的值,会影响到解构赋值对它的引用。

由于数组是特殊的对象,所以对象的扩展运算符也可以用于数组。

let foo = { ...['a', 'b', 'c'] }
foo
// {0: "a", 1: "b", 2: "c"}

如果扩展运算符后面不是对象,则会自动将其转为对象。

// 等同于 {...Object(1)}
{...1} // {}

// 等同于 {...Object(true)}
{...true} // {}

// 等同于 {...Object(undefined)}
{...undefined} // {}

// 等同于 {...Object(null)}
{...null} // {}

对象的扩展运算符等同于使用 Object.assign()方法。

let aClone = { ...a }
// 等同于
let aClone = Object.assign({}, a)

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

const obj = {
  ...(x > 1 ? { a: 1 } : {}),
  b: 2,
}

扩展运算符的参数对象之中,如果有取值函数 get,这个函数是会执行的。

let a = {
  get x() {
    throw new Error('not throw yet')
  },
}

let aWithXGetter = { ...a } // 报错
Copyright © 零度实验室 2020 all right reserved,powered by Gitbook修订时间: 2021-07-02 10:46:52

results matching ""

    No results matching ""