假设我有一个选项变量我想设置一个默认值。

这两种选择的优点/缺点是什么?

使用对象扩展

options = {...optionsDefault, ...options};

或者使用Object.assign

options = Object.assign({}, optionsDefault, options);

这是让我疑惑的承诺。


当前回答

(1)创建对象的浅副本和(2)将多个对象合并为单个对象的方法在2014年至2018年之间有了很大的发展。

下面概述的方法在不同时期变得可用并广泛使用。这个答案提供了一些历史视角,但并不详尽。

如果没有库或现代语法的帮助,您将使用for-in循环,例如。 var mergedOptions = {} for (var键在defaultOptions) { mergedOptions[key] = defaultOptions[key] } 对于(var键在选项中){ mergedOptions[key] = options[key] } options = mergedOptions

2006

jQuery 1.0有jQuery.extend(): 选项= $。extend({}, defaultOptions, options)

2010

下划线。js 1.0有_.extend() 选项= _。extend({}, defaultOptions, options)

2014

2ality发布了一篇关于Object.assign()加入ES2015的文章 对象分配发布到npm。 var objectAssign = require('object-assign') options = objectAssign({}, defaultOptions, options) ES2016提出的对象Rest/扩展属性语法。

2015

对象。Chrome (45), Firefox(34)和Node.js(4)都支持assign。不过,旧的运行时需要Polyfill。 options =对象。assign({}, defaultOptions, options) 对象Rest/Spread Properties提案进入第二阶段。

2016

对象Rest/扩展属性语法没有被包含在ES2016中,但是提案已经到了第三阶段。

2017

对象Rest/Spread属性语法没有包含在ES2017中,但在Chrome (60), Firefox(55)和Node.js(8.3)中可用。不过,旧的运行时需要一些编译。 选项={…defaultOptions,…选择}

2018

对象Rest/Spread Properties提案达到了第4阶段,语法被包含在ES2018标准中。

其他回答

(1)创建对象的浅副本和(2)将多个对象合并为单个对象的方法在2014年至2018年之间有了很大的发展。

下面概述的方法在不同时期变得可用并广泛使用。这个答案提供了一些历史视角,但并不详尽。

如果没有库或现代语法的帮助,您将使用for-in循环,例如。 var mergedOptions = {} for (var键在defaultOptions) { mergedOptions[key] = defaultOptions[key] } 对于(var键在选项中){ mergedOptions[key] = options[key] } options = mergedOptions

2006

jQuery 1.0有jQuery.extend(): 选项= $。extend({}, defaultOptions, options)

2010

下划线。js 1.0有_.extend() 选项= _。extend({}, defaultOptions, options)

2014

2ality发布了一篇关于Object.assign()加入ES2015的文章 对象分配发布到npm。 var objectAssign = require('object-assign') options = objectAssign({}, defaultOptions, options) ES2016提出的对象Rest/扩展属性语法。

2015

对象。Chrome (45), Firefox(34)和Node.js(4)都支持assign。不过,旧的运行时需要Polyfill。 options =对象。assign({}, defaultOptions, options) 对象Rest/Spread Properties提案进入第二阶段。

2016

对象Rest/扩展属性语法没有被包含在ES2016中,但是提案已经到了第三阶段。

2017

对象Rest/Spread属性语法没有包含在ES2017中,但在Chrome (60), Firefox(55)和Node.js(8.3)中可用。不过,旧的运行时需要一些编译。 选项={…defaultOptions,…选择}

2018

对象Rest/Spread Properties提案达到了第4阶段,语法被包含在ES2018标准中。

作为参考,对象rest/spread在ECMAScript 2018中作为第4阶段完成。提案可以在这里找到。

在大多数情况下,对象赋值和扩展的工作方式是相同的,关键的区别是扩展定义属性,而object .assign()设置属性。这意味着Object.assign()触发设置器。

值得记住的是,除此之外,对象rest/spread 1:1映射到object .assign(),与数组(可迭代)spread的作用不同。例如,当展开一个数组时,将展开空值。然而,使用对象传播时,空值会被无声地传播到空值。

数组(可迭代)扩展示例

const x = [1, 2, null , 3];
const y = [...x, 4, 5];
const z = null;

console.log(y); // [1, 2, null, 3, 4, 5];
console.log([...z]); // TypeError

对象扩展示例

const x = null;
const y = {a: 1, b: 2};
const z = {...x, ...y};

console.log(z); //{a: 1, b: 2}

这与Object.assign()的工作方式是一致的,两者都无声地排除空值而没有错误。

const x = null;
const y = {a: 1, b: 2};
const z = Object.assign({}, x, y);

console.log(z); //{a: 1, b: 2}

我们将创建一个名为identity的函数,它只返回我们给它的任何参数。

identity = (arg) => arg

和一个简单的数组。

arr = [1, 2, 3]

如果用arr求恒等函数,我们知道会发生什么

当你必须使用Object.assign时,我想添加这个简单的例子。

class SomeClass {
  constructor() {
    this.someValue = 'some value';
  }

  someMethod() {
    console.log('some action');
  }
}


const objectAssign = Object.assign(new SomeClass(), {});
objectAssign.someValue; // ok
objectAssign.someMethod(); // ok

const spread = {...new SomeClass()};
spread.someValue; // ok
spread.someMethod(); // there is no methods of SomeClass!

使用JavaScript时可能不清楚。但是如果你想创建一些类的实例,使用TypeScript会更容易

const spread: SomeClass = {...new SomeClass()} // Error

对象。当目标对象是一个常量并且您希望一次设置多个属性时,Assign是必要的。

例如:

const target = { data: "Test", loading: true }

现在,假设你需要用一个源的所有属性来改变目标:

const source = { data: null, loading: false, ...etc }

Object.assign(target, source) // Now target is updated
target = { ...target, ...source) // Error: cant assign to constant

请记住,您正在改变目标obj,所以尽可能使用Object。分配空目标或扩散分配给一个新的obj。