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

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

使用对象扩展

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

或者使用Object.assign

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

这是让我疑惑的承诺。


当前回答

作为参考,对象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}

其他回答

这现在是ES6的一部分,因此是标准化的,并且在MDN上也有文档: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator

它使用起来非常方便,与对象解构一起使用也很有意义。

上面列出的另一个优势是object. assign()的动态功能,不过这就像在文字对象中展开数组一样简单。在编译后的babel输出中,它完全使用了Object.assign()所演示的内容

因此,正确的答案是使用object spread,因为它现在是标准化的,被广泛使用(参见react, redux等),易于使用,并且具有object .assign()的所有特性。

正如其他人所提到的,在撰写本文时,object .assign()需要一个polyfill和object spread…需要一些蒸煮(也许是一个填充)为了工作。

考虑下面的代码:

// Babel wont touch this really, it will simply fail if Object.assign() is not supported in browser.
const objAss = { message: 'Hello you!' };
const newObjAss = Object.assign(objAss, { dev: true });
console.log(newObjAss);

// Babel will transpile with use to a helper function that first attempts to use Object.assign() and then falls back.
const objSpread = { message: 'Hello you!' };
const newObjSpread = {...objSpread, dev: true };
console.log(newObjSpread);

它们都产生相同的输出。

下面是从Babel到ES5的输出:

var objAss = { message: 'Hello you!' };
var newObjAss = Object.assign(objAss, { dev: true });
console.log(newObjAss);

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var objSpread = { message: 'Hello you!' };
var newObjSpread = _extends({}, objSpread, { dev: true });
console.log(newObjSpread);

这是我目前的理解。object .assign()实际上是标准化的,其中随着对象扩展…还没有。唯一的问题是浏览器对前者以及未来对后者的支持。

玩一下这里的代码

希望这能有所帮助。

其他答案都老了,得不到好的答案。 下面的例子是对象字面量,有助于两者如何相互补充,以及如何不能相互补充(因此存在差异):

var obj1 = { a: 1,  b: { b1: 1, b2: 'b2value', b3: 'b3value' } };

// overwrite parts of b key
var obj2 = {
      b: {
        ...obj1.b,
        b1: 2
      }
};
var res2 = Object.assign({}, obj1, obj2); // b2,b3 keys still exist
document.write('res2: ', JSON.stringify (res2), '<br>');
// Output:
// res2: {"a":1,"b":{"b1":2,"b2":"b2value","b3":"b3value"}}  // NOTE: b2,b3 still exists

// overwrite whole of b key
var obj3 = {
      b: {
        b1: 2
      }
};
var res3 = Object.assign({}, obj1, obj3); // b2,b3 keys are lost
document.write('res3: ', JSON.stringify (res3), '<br>');
// Output:
  // res3: {"a":1,"b":{"b1":2}}  // NOTE: b2,b3 values are lost

这里还有几个小例子,同样是数组和对象: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

展开运算符将数组展开到函数的单独参数中。

let iterableObjB = [1,2,3,4]
function (...iterableObjB)  //turned into
function (1,2,3,4)

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

identity = (arg) => arg

和一个简单的数组。

arr = [1, 2, 3]

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