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
。
题
- 有没有更好的方式来传递对象的价值,而不是创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);
x
和x1
将是两个不同的对象, 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);
使用ES6语法:
let obj = Object.assign({}, o);