JavaScript:如何通过值传递对象?
当将对象作为参数传递时,JavaScript通过引用传递它们,这使得创建对象的本地副本变得困难JavaScript:如何通过值传递对象?,javascript,Javascript,当将对象作为参数传递时,JavaScript通过引用传递它们,这使得创建对象的本地副本变得困难 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])
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
问题:
您对JavaScript中对象的工作方式有点困惑。对象的引用是变量的值。没有未序列化的值。创建对象时,其结构存储在内存中,分配给它的变量保存对该结构的引用 即使你所要求的是以某种简单的母语结构提供的,从技术上讲,它仍然是克隆
JavaScript实际上只是传递值。。。只是传递的值可能是对某个对象的引用。Javascript总是按值传递。在本例中,它将引用
o
的副本传递到匿名函数中。代码正在使用引用的副本,但它正在改变单个对象。除了值之外,没有办法让javascript传递任何东西
在这种情况下,您需要传递基础对象的副本。克隆对象是唯一的办法。不过,您的克隆方法需要一些更新
function ShallowCopy(o) {
var copy = Object.create(o);
for (prop in o) {
if (o.hasOwnProperty(prop)) {
copy[prop] = o[prop];
}
}
return copy;
}
不是真的
根据实际需要,一种可能是将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
具有引用另一个对象(如数组)的属性,则需要确保在向对象添加成员之前对该对象进行阴影处理,否则,这些成员将添加到obj
,并在原型链中具有obj
的所有对象之间共享
var o = {
baz: []
};
(function(x){
var obj = Object.create( x );
obj.baz.push( 'new value' );
})(o);
alert( o.baz[0] ); // 'new_value'
在这里您可以看到,由于您没有在o
上使用baz
属性对obj
上的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 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)
归结起来,这只是一个非常复杂的代理,但也许可以做到
var o = {
a: 'a',
b: 'b',
func: function() { return 'func'; }
};
var proxy = Proxy.create(handlerMaker(o), o);
(function(x){
var obj = x;
console.log(x.a);
console.log(x.b);
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() {}
};
}
作为jQuery用户的一个考虑因素,还有一种方法可以使用框架以简单的方式实现这一点。这是jQuery让我们的生活更轻松的另一种方式
var oShallowCopy = jQuery.extend({}, o);
var oDeepCopy = jQuery.extend(true, {}, o);
参考资料:
- 并深入挖掘源头李>
JSON.parse(JSON.stringify(obj))
是一种快速复制对象的方法,前提是您的对象可以序列化为JSON。使用此方法
x = Object.create(x1);
x
和x1
将是两个不同的对象,x
中的更改不会更改x1
如果使用lodash或npm
,请使用lodash的合并功能将对象的所有属性深度复制到新的空对象,如下所示:
var objectCopy=lodash.merge({},originalObject)代码>
使用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.
我需要按值(非引用)复制对象,我发现此页面很有用:
。特别是,John Resig使用以下代码克隆对象:
//Shallow copy
var newObject = jQuery.extend({}, oldObject);
// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);
使用ES6语法:
让obj=Object.assign({},o)代码>实际上,Javascript总是通过值传递。但由于对象引用是值,因此对象的行为将类似于通过引用传递的
因此,为了解决这个问题,字符串化对象并解析对象,两者都使用JSON。请参见下面的代码示例:
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
ES6
使用扩展运算符,如obj2={…obj1}
将具有相同的值,但引用不同
ES5
使用Object.assignobj2=Object.assign({},obj1)
您需要这个的用例是什么?编程乐趣。看看新的JS引擎是否已经解决了这个问题(从技术上讲,它是通过值传递引用),但主要是为了好玩。与Java一样,当向函数传递对象时,它按值传递,但值是引用。另请参见。据我所知,不能按值传递对象。即使有,它实际上是在做你上面提到的克隆,所以我看不出有什么好处。除了可能节省3行代码之外。@vol7ron是的,他们通过正确实现语言设计特性解决了这个问题。+1,我打算在回答中建议Object.create
,但我不想详细解释副本的肤浅;-)+我忘了这件事。我确实试过var obj=new Object(x)
。对我来说,我认为newobject(x)
将执行Object.create(x)
默认情况下-interesting@vol7ron:是的,新对象(x)
只是吐出相同的对象(正如您可能注意到的)。如果有一种本地的克隆方式就好了。不确定是否有什么在工作中。+1表示“总是通过值传递”,尽管我更喜欢使用(作为对立面)