【问题标题】:side affecting new object is changing the original object影响新对象的一面是改变原始对象
【发布时间】:2016-11-30 22:04:11
【问题描述】:

预期结果

我编写了一个函数来获取一个简单的对象字面量,并重新格式化它,如下例所示:

var original = { a: 1, b: true, c: "a string" }

// run through function ...

var result = { 
  a: { type: "int", val: 1 }, 
  b: { type: "bit", val: 1 }, 
  c: { type: "varchar(250)", val: "a string" }
}

当前解决方案

该函数起作用,使用for ... in 循环迭代原始对象并基于原始数据构建一个新对象。

function change (data) {

  function loop (d) {

    var orig = d;
    var end = d;

    for (var key in orig) {

      var property = {
        type: "test",
        val: orig[key]
      };

      end[key] = property;
    }

    return end;
  }

  // create object using loop & return
  var p = loop(data);
  return p;

}

实际结果

然而,这个函数也改变了传入的 original 对象,我似乎不知道为什么。

var original = { a: 1, b: true, c: "a string" }

// run through function ...
var result = change(original);  

console.log(result);    // =>  { 
                        //        a: { type: "int", val: 1 }, 
                        //        b: { type: "bit", val: 1 }, 
                        //        c: { type: "varchar(250)", val: "a string" }
                        //      }

console.log(original);  // =>  { 
                        //        a: { type: "int", val: 1 }, 
                        //        b: { type: "bit", val: 1 }, 
                        //        c: { type: "varchar(250)", val: "a string" }
                        //      }
                        // instead of expected: 
                        //      { a:1, b:true, c:"a string" }

我猜这与我不完全理解 javascript 的范围有关,可能与原型继承有关(我肯定需要了解更多),但此时我只是不确定在哪里开始真正了解这里发生了什么。当我将它与我对 JavaScript 中副作用的简单理解进行比较时,我感到更加困惑:

var a = 1;
var b = a;
console.log(a) // => 1
console.log(b) // => 1

b = 2
console.log(a) // => 1
console.log(b) // => 2

该函数按原样工作,并在我的程序的其余部分执行我需要的操作,但这个问题真的让我很困扰,因为我不明白这里发生了什么。

【问题讨论】:

  • var newObject = oldObject 不创建 oldObject 的副本
  • 所以,对函数中 orig、end 或 d 属性的任何更改也会更改原始属性
  • 只需定义var end = {} 即可解决您的问题
  • @JaromandaX 是的,这似乎正是正在发生的事情。我该如何避免呢?我猜这是我忽略的非常简单的事情,但我似乎无法弄清楚......

标签: javascript inheritance scope


【解决方案1】:

在 Javascript 中,当一个对象作为参数传递时,如果您决定在函数中对其进行变异,该函数将作为对原始对象的引用并且也会对其进行变异。

如果你只是像只读一样处理它,它就像一个常规参数(按值传递)

对于扁平的对象(不包含嵌套对象),您可以使用Object.assign(具有可用 polyfill 的 Es6 功能)

let obj1 = { a: 1};
let obj2 = Object.assign({}, obj1);

对于更复杂的对象,我建议你使用一些库方法,比如 lodash 的 _.cloneDeep

// you have to include lodash.js in your page
let obj1 = { a: 1};
let obj2 = _.cloneDeep(obj1);

或jQuery的$.extend

// you have to include jquery.js in your page
let obj1 = { a: 1};
let obj2 = $.extend(true, {}, obj1);

【讨论】:

  • 非常感谢,这真的很有帮助!
  • @guest271314 谢谢。我的错。打算写关于Object.assign。更新
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-23
  • 1970-01-01
  • 2015-02-03
  • 2012-12-13
  • 2020-08-09
  • 1970-01-01
  • 2013-03-29
相关资源
最近更新 更多