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])

当将对象作为参数传递时,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


  • 问题:
  • 除了创建本地副本/克隆之外,还有更好的方法按值传递对象吗

  • 您对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.assign
    obj2=Object.assign({},obj1)

    您需要这个的用例是什么?编程乐趣。看看新的JS引擎是否已经解决了这个问题(从技术上讲,它是通过值传递引用),但主要是为了好玩。与Java一样,当向函数传递对象时,它按值传递,但值是引用。另请参见。据我所知,不能按值传递对象。即使有,它实际上是在做你上面提到的克隆,所以我看不出有什么好处。除了可能节省3行代码之外。@vol7ron是的,他们通过正确实现语言设计特性解决了这个问题。+1,我打算在回答中建议
    Object.create
    ,但我不想详细解释副本的肤浅;-)+我忘了这件事。我确实试过
    var obj=new Object(x)
    。对我来说,我认为
    newobject(x)
    将执行
    Object.create(x)
    默认情况下-interesting@vol7ron:是的,
    新对象(x)
    只是吐出相同的对象(正如您可能注意到的)。如果有一种本地的克隆方式就好了。不确定是否有什么在工作中。+1表示“总是通过值传递”,尽管我更喜欢使用(作为对立面)