JavaScript:如何按值传递对象?

IT技术 javascript
2021-02-04 18:49:37
  • 将对象作为参数传递时,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


问题

  1. 除了创建本地副本/克隆之外,有没有更好的方法来按值传递对象?
6个回答

并不真地。

根据您的实际需要,一种可能性可能是设置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'

在这里,你可以看到,因为你没在阴影阵列bazo有一个baz关于财产objo.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,我也打算Object.create在我的答案中提出建议,但我不想解释副本的肤浅;-)
2021-03-17 18:49:37
@vol7ron:是的,new Object(x)只是吐出同一个物体(你可能已经注意到了)如果有一种本地的克隆方式就好了。不确定是否有任何工作。
2021-03-23 18:49:37
+1,我忘了这个。我确实尝试过var obj = new Object(x)对我来说,我认为默认情况下new Object(x)会执行Object.create(x)- 有趣
2021-04-10 18:49:37

查看此答案https://stackoverflow.com/a/5344074/746491

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

我倾向于避免这种情况,因为对象不能总是被序列化,并且因为在像 IE7/8 这样的中年浏览器中,JSON不包括在内并且需要定义 - 也可以使用像Clone. 然而,我怀疑我的观点在未来可能会改变,因为 JSON 更多地集成到非基于浏览器的软件中,如数据库和 IDE
2021-03-16 18:49:37
真的?!?序列化为 JSON 只是为了创建对象副本?讨厌这种荒谬语言的另一个原因。
2021-03-16 18:49:37
Object.create() 在 NodeJS 上对我不起作用。您的解决方案解决了我的问题。
2021-03-25 18:49:37
序列化JSON真的是一种快速复制的方式吗?根据 NodeJS 文档,JSON 操作是 CPU 最密集的任务。nodejs.org/en/docs/guides/dont-block-the-event-loop/...
2021-04-05 18:49:37
如果没有函数和日期对象,JSON.parse 解决方案似乎是最好的。stackoverflow.com/questions/122102/...
2021-04-07 18:49:37

这是将执行对象深度复制的克隆函数:

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)
这是一个深刻的答案。
2021-03-25 18:49:37
美丽的!最佳答案 海事组织。
2021-03-30 18:49:37
我的上帝在所有答案中这一个真的有效!!!谢谢!!!3 天后,我终于完成了!!!
2021-04-03 18:49:37

利用 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

同意。相应地更新答案。此外,并非每个浏览器都支持assign() 方法。根据您的兼容性要求,可能需要使用像 MDN 上的 polyfill。
2021-03-17 18:49:37
@Brandon,在您提供的链接中,它给出了深度克隆的警告:“对于深度克隆,我们需要使用其他替代方法,因为 Object.assign() 复制属性值。如果源值是对对象的引用,它只复制该参考值。”
2021-03-21 18:49:37
这是可行的,但请记住,它不会执行深度复制,其中包含的任何对象a都将被复制为引用。
2021-04-01 18:49:37
更好的: var b = Object.assign({}, a);
2021-04-12 18:49:37

用这个

x = Object.create(x1);

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

我最终使用了 Object.assign()。对于简单的测试用例, .create() 有效,但对于更复杂的(我还找不到模式),它仍然引用相同的地址。
2021-03-15 18:49:37
我尝试在删除操作后打印这两个对象,它反映在两个对象中
2021-04-04 18:49:37
如果对象的值不是通过引用存储的,即它们是原始数据类型,如数字或布尔值,它不仅会改变。例如,考虑下面的代码 a = {x:[12], y:[]}; b = Object.create(a); bxpush(12); 控制台日志(轴);
2021-04-12 18:49:37