Object.Assign()函数生成的复制对象有副作用吗?

时间:2016-02-05 21:11:02

标签: javascript javascript-objects

我有一个名为 result 的对象,它由两个对象组成,如:

const a = {bar: {baz: 2}};
var b = {foo: 1};
var result = Object.assign({}, a, b);
console.log(result, a, b);
// result -> {bar: {baz: 2}, foo: 1}
// a -> {bar: {baz: 2}}
// b -> {foo: 1}

现在,我正在更改结果对象的 bar 属性,如:

result.bar.baz = 3;
result.foo = 4;
console.log(result, a, b);
// result -> {bar: {baz: 3}, foo: 4}
// a -> {bar: {baz: 3}} intresting part
// b -> {foo: 1} intresting, too!

(您可以将代码复制并粘贴到javascript控制台,以便顺便查看这两种情况的结果)

这里有两件奇怪的事情。第一个是我正在更改结果对象的属性,但常量对象 a 的属性也会更改。即使第一个是Object.assign函数的情况,我如何更改常量变量?假设const变量突变就是这种情况,那么为什么属性 foo 的变化不会反映到对象b? 我之所以这样,是因为我通常使用 Object.assign 来复制对象,但我觉得这个函数非常奇怪。有关此案的任何想法?谢谢。

2 个答案:

答案 0 :(得分:1)

使用const声明变量只会阻止它更改为其他值。它不会阻止该值引用的数据发生变化。

const foo = {prop: 'bar'};
foo.prop = 'baz'; // Works well
foo = 'baz'; // TypeError: invalid assignment to const `foo'

如果您想阻止更改对象,可以freeze

Object.freeze(foo);
foo.prop = 'buz'; // TypeError: "prop" is read-only

但是,这只会影响自己的属性。如果其中一个的值是另一个对象,它就不会被冻结。

Object.assign也会发生这种情况。它只复制自己的属性,如果它们的值是一个对象,它就不会克隆"克隆"它。也就是说,引用仍然是相同的,并且将反映更改。

如果要深度克隆对象,请参阅What is the most efficient way to clone an object?

答案 1 :(得分:0)

Object.assign将起作用,但添加了一个问题,如果您分配的任何属性包含一个对象作为值,它不会创建该对象的副本,因此引用不会更改,属性在created对象将指向同一个嵌套对象。

javascript中的常量也可能是欺骗性的,您可以在“常量”中添加和删除属性。对象,只要您不尝试将其重新分配给新对象或其他原语。

数组也会出现同样的问题,你可以创建一个' const'数组,但推出它。

https://jsfiddle.net/eu9yg37s/6/只是我正在弄乱的东西试图展示我的意思。

const a = {bar: {baz: 2}};
var b = {foo: 1};

// Example of customizer function that may take into account nested objects and properly copy them using lodash 4.x
var customizer = function(objValue, srcValue) {
  if (typeof srcValue === 'object' && typeof srcValue !== null) {
    return _.assignWith({}, srcValue, customizer);
  }
  return _.isUndefined(objValue) ? srcValue : objValue;
}

// This calls assign, but will invoke the customizer function
var result = _.assignWith({}, a, b, customizer);

result.bar.baz = 3;
result.foo = 4;
console.log(result, a, b);

// 'Constant' Array Example
const hi = [true, false, 'hi'];

hi[2] = 23;
console.log('hi.pop', hi.pop());
console.log('hi', hi);

// These will error, uncomment out to see it errors on any of these attempts
//hi = 3;
//hi = 'no';
hi = [true, false, 23];
//hi = false;
//hi = {};

更改并未反映在b中,因为在分配操作期间它不是嵌套对象,因此我们创建的对象中的属性foo指向新原语1