JavaScript:如何通过值传递对象?

  • 当传递对象作为参数时,JavaScript通过引用传递对象,并且很难创build对象的本地副本。

    var o = {}; (function(x){ var obj = x; obj.foo = 'foo'; obj.bar = 'bar'; })(o) 

    o将有.foo.bar

  • 可以通过克隆来解决这个问题。 简单的例子:

     var o = {}; function Clone(x) { for(p in x) this[p] = (typeof(x[p]) == 'object')? new Clone(x[p]) : x[p]; } (function(x){ var obj = new Clone(x); obj.foo = 'foo'; obj.bar = 'bar'; })(o) 

    o不会有.foo.bar


  1. 有没有更好的方式来传递对象的价值,而不是创build一个本地副本/克隆?

不是真的。

根据你实际需要,一种可能性可能是将o设置为新对象的原型。

 var o = {}; (function(x){ var obj = Object.create( x ); obj.foo = 'foo'; obj.bar = 'bar'; })(o); alert( o.foo ); // undefined 

所以你添加到obj任何属性都不会被添加到o 。 任何添加到obj中的属性都与o属性相同,会影响o属性。

当然,任何添加到o属性都可以从obj获得,如果它们没有被遮挡,那么在原型链中有o所有对象都会看到与o相同的更新。

而且,如果obj有一个引用另一个对象的属性,比如一个Array,那么在将对象添加到对象之前,您需要确保将对象隐藏起来,否则,这些成员将被添加到obj ,并且会被共享在原型链中具有obj对象。

 var o = { baz: [] }; (function(x){ var obj = Object.create( x ); obj.baz.push( 'new value' ); })(o); alert( o.baz[0] ); // 'new_value' 

在这里你可以看到,因为你没有在obj上的baz属性上o.baz数组,所以o.baz数组被修改。

所以相反,你需要先把它遮蔽一下:

 var o = { baz: [] }; (function(x){ var obj = Object.create( x ); obj.baz = []; obj.baz.push( 'new value' ); })(o); alert( o.baz[0] ); // undefined 

这是克隆function,将执行该对象的深层复制:

 function clone(obj){ if(obj == null || typeof(obj) != 'object') return obj; var temp = new obj.constructor(); for(var key in obj) temp[key] = clone(obj[key]); return temp; } 

现在你可以像这样使用:

 (function(x){ var obj = clone(x); obj.foo = 'foo'; obj.bar = 'bar'; })(o) 

看看这个答案https://stackoverflow.com/a/5344074/746491

简而言之, JSON.parse(JSON.stringify(obj))是一种复制对象的快速方法,如果对象可以被序列化为json。

对于JavaScript中对象的工作方式,你有点困惑。 对象的引用variables的值。 没有非序列化的价值。 当你创build一个对象时,它的结构被存储在内存中,并且被赋值的variables将持有对该结构的引用。

即使你所要求的东西是用某种简单的本地语言来构build的,它在技术上仍然是克隆的。

JavaScript实际上只是传值而已……只是传递的值可能是对某事的引用。

使用Object.assign()

例:

 var a = {some: object}; var b = new Object; Object.assign(b, a); // b now equals a, but not by association. 

一个干净的例子,做同样的事情:

 var a = {some: object}; var b = Object.assign({}, a); // Once again, b now equals a. 

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

JavaScript总是传递价值。 在这种情况下,它将引用o的副本传递给匿名函数。 代码正在使用引用的副本,但它正在改变单个对象。 没有办法使JavaScript通过除了价值以外的任何东西。

在这种情况下,你想要传递一个底层对象的副本。 克隆物体是唯一的办法。 尽pipe你的克隆方法需要一些更新

 function ShallowCopy(o) { var copy = Object.create(o); for (prop in o) { if (o.hasOwnProperty(prop)) { copy[prop] = o[prop]; } } return copy; } 

作为jQuery用户的考虑事项,还有一种方法可以使用框架以简单的方式执行此操作。 另一种方式jQuery使我们的生活更容易一些。

 var oShallowCopy = jQuery.extend({}, o); var oDeepCopy = jQuery.extend(true, {}, o); 

参考:

用这个

 x = Object.create(x1); 

xx1将是两个不同的对象, x变化不会改变x1

我需要通过值复制一个对象(不参考),我发现这个页面有帮助:

什么是在JavaScript中深入克隆对象的最有效方法? 。 特别是,John Resig用下面的代码克隆一个对象:

 //Shallow copy var newObject = jQuery.extend({}, oldObject); // Deep copy var newObject = jQuery.extend(true, {}, oldObject); 

其实,Javascript总是传递价值 。 但是因为对象引用是 ,所以对象的行为就像通过引用传递一样。

所以为了解决这个问题,使用JSON对对象进行string化parsing它。 看下面的代码示例:

 var person = { Name: 'John', Age: '21', Gender: 'Male' }; var holder = JSON.stringify(person); // value of holder is "{"Name":"John","Age":"21","Gender":"Male"}" // note that holder is a new string object var person_copy = JSON.parse(holder); // value of person_copy is { Name: 'John', Age: '21', Gender: 'Male' }; // person and person_copy now have the same properties and data // but are referencing two different objects 

当你归结它,它只是一个看上去过于复杂的代理,但也许Catch-All代理可以做到这一点?

 var o = { a: 'a', b: 'b', func: function() { return 'func'; } }; var proxy = Proxy.create(handlerMaker(o), o); (function(x){ var obj = x; console.log(xa); console.log(xb); obj.foo = 'foo'; obj.bar = 'bar'; })(proxy); console.log(o.foo); function handlerMaker(obj) { return { getOwnPropertyDescriptor: function(name) { var desc = Object.getOwnPropertyDescriptor(obj, name); // a trapping proxy's properties must always be configurable if (desc !== undefined) { desc.configurable = true; } return desc; }, getPropertyDescriptor: function(name) { var desc = Object.getOwnPropertyDescriptor(obj, name); // not in ES5 // a trapping proxy's properties must always be configurable if (desc !== undefined) { desc.configurable = true; } return desc; }, getOwnPropertyNames: function() { return Object.getOwnPropertyNames(obj); }, getPropertyNames: function() { return Object.getPropertyNames(obj); // not in ES5 }, defineProperty: function(name, desc) { }, delete: function(name) { return delete obj[name]; }, fix: function() {} }; } 

如果你正在使用lodash或者npm ,使用lodash的合并function将所有对象的属性深度复制到一个新的空对象,如下所示:

var objectCopy = lodash.merge({}, originalObject);

https://lodash.com/docs#merge

https://www.npmjs.com/package/lodash.merge

使用ES6语法:

let obj = Object.assign({}, o);