将对象作为参数传递时,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]) == 'object')? new Clone(x[p]) : x[p];
}
(function(x){
var obj = new Clone(x);
obj.foo = 'foo';
obj.bar = 'bar';
})(o)
o
不会有.foo
或.bar
。
答案 0 :(得分:54)
不是。
根据您的实际需要,一个可能性可能是将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
具有引用另一个对象(如数组)的属性,则在向对象添加成员之前,您需要确保隐藏该对象,否则,这些成员将被添加到{ {1}},并将在原型链中具有obj
的所有对象之间共享。
obj
在这里你可以看到,因为你没有var o = {
baz: []
};
(function(x){
var obj = Object.create( x );
obj.baz.push( 'new value' );
})(o);
alert( o.baz[0] ); // 'new_value'
baz
o
上baz
的{{1}} obj
属性,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
答案 1 :(得分:35)
这是克隆函数,它将执行对象的深层复制:
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)
答案 2 :(得分:33)
查看此答案https://stackoverflow.com/a/5344074/746491。
简而言之,JSON.parse(JSON.stringify(obj))
是一种快速复制对象的方法,如果您的对象可以序列化为json。
答案 3 :(得分:16)
使用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
答案 4 :(得分:15)
您对JavaScript中的对象工作方式有点困惑。对象的引用是变量的值。没有反序列化的价值。创建对象时,其结构存储在内存中,并且分配给它的变量保存对该结构的引用。
即使你所要求的是某种简单的本地语言结构,它在技术上仍然是克隆。
JavaScript实际上只是按值传递......只是传递的值可能是对某事的引用。
答案 5 :(得分:12)
使用此
x = Object.create(x1);
x
和x1
将是两个不同的对象,x
中的更改不会更改x1
答案 6 :(得分:8)
Javascript总是按值传递。在这种情况下,它将引用o
的副本传递给匿名函数。代码正在使用引用的副本,但它正在改变单个对象。没有办法让javascript通过除value之外的任何东西。
在这种情况下,您想要的是传递底层对象的副本。克隆对象是唯一的办法。你的克隆方法需要一些更新,但
function ShallowCopy(o) {
var copy = Object.create(o);
for (prop in o) {
if (o.hasOwnProperty(prop)) {
copy[prop] = o[prop];
}
}
return copy;
}
答案 7 :(得分:7)
作为jQuery用户的考虑因素,还有一种方法可以使用框架以简单的方式完成此操作。换句话说,jQuery让我们的生活变得更轻松。
var oShallowCopy = jQuery.extend({}, o);
var oDeepCopy = jQuery.extend(true, {}, o);
参考:
答案 8 :(得分:6)
实际上,Javascript总是按值传递。但由于对象引用为值,因此对象的行为类似于通过引用传递。
因此,为了绕过这个, stringify 对象,然后解析,两者都使用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
答案 9 :(得分:2)
我需要按值复制对象(不是引用),我觉得这个页面很有用:
What is the most efficient way to deep clone an object in JavaScript?。特别是,使用John Resig的以下代码克隆对象:
//Shallow copy
var newObject = jQuery.extend({}, oldObject);
// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);
答案 10 :(得分:2)
使用ES6语法:
let obj = Object.assign({}, o);
答案 11 :(得分:1)
当你归结为它时,它只是一个花哨的过于复杂的代理,但也许Catch-All Proxies可以做到这一点?
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() {}
};
}
答案 12 :(得分:0)
如果您使用的是lodash或npm
,请使用lodash的合并功能将所有对象的属性深层复制到一个新的空对象,如下所示:
var objectCopy = lodash.merge({}, originalObject);
答案 13 :(得分:0)
使用obj2 = {... obj1} 现在两个对象具有相同的值,但引用不同