【问题标题】:javascript pass object as referencejavascript传递对象作为参考
【发布时间】:2013-05-28 15:22:20
【问题描述】:

我有一个对象,它在函数内的许多不同函数中传递。这些函数可能会也可能不会改变对象的值,但如果他们确实改变了它,那么我想获得对象的最新更改。

以下是我想要做的:

var ob = {text: 'this is me', name: 'john'}

function (object) {

     changeObject(object);
     customObjectChanger(object);
     callback = function (object) {
          object.text = 'new text';
     }

     callback(object);

     // object value here should be object{text: 'new text', name: 'john'};    
}

【问题讨论】:

  • Javascript 一直自动通过引用传递对象。您是否尝试过上面的代码,看看它是否已经完成了您想要的操作?
  • 不,我没有。我确实读过它。只是想在这里确认一下。
  • JavaScript Pass By Reference。但是,JavaScript在对象被传递或分配时不会复制对象。因此,它是具有不同名称的 same 对象 - 对对象所做的更改(从任何名称)都会影响所述对象。
  • 这取决于您所说的“通过引用”。在我看来,“同一个对象,不同的名字”就是引用的定义。
  • @jcsanyi 这就是为什么定义术语和避免歧义很重要。 (维基百科的文章确实承认该术语是模棱两可的,这就是为什么我尝试避免使用“通过引用”,除非明确意味着更改本地名称绑定会影响调用者。)

标签: javascript variables object reference pass-by-reference


【解决方案1】:

在 JavaScript 中,对象总是通过复制引用传递。我不确定这是否是完全正确的术语,但会传入对象引用的副本。

这意味着对对象所做的任何更改都将在函数执行完成后对您可见。

代码:

var obj = {
  a: "hello"
};

function modify(o) {
  o.a += " world";
}

modify(obj);
console.log(obj.a); //prints "hello world"

话虽如此,由于它只是传入的引用的副本,如果您重新分配函数内部的对象,这将在函数之外不可见,因为它只是您更改的引用的副本

代码:

var obj = {
  a: "hello"
};

function modify(o) {
  o = {
    a: "hello world"
  };
}

modify(obj);
console.log(obj.a); //prints just "hello"

【讨论】:

  • en.wikipedia.org/wiki/Evaluation_strategy - 我更喜欢“通过 [对象] 共享调用”,因为它的直接性、实现关注点的分离以及减少与其他调用约定的歧义。 ECMAScript 在规范的任何部分为此目的使用“参考”。 (参考规范类型不适用于函数调用。)
  • +1 可以清楚地描述与传统传递引用的不同之处。
  • 我想我已经明确传递了对象引用的副本,而不是对象本身。
  • 我该如何处理这个问题?如果我想更改对象本身而不是其复制引用怎么办?
  • @Abhinav1602 我想在函数中重新分配一个对象,它的新值在调用函数中可见。
【解决方案2】:

“对象”不是 JavaScript 中的值,不能“通过”。

您处理的所有值都是引用(指向对象的指针)。

传递或分配一个引用会给出另一个指向同一个对象的引用。当然,您可以通过其他引用修改同一个对象。

【讨论】:

  • 确实——所以对对象的引用的副本是...“通过”-_-
  • 确实不会传递对象,但会传递引用,如果在接收器函数内部更改属性,您可以修改其属性
  • 简单、简洁的答案。将对象分配给变量时,分配的值是对该对象的引用。所以所有变量都有一个值,但有些值是对对象的引用(例如对象、函数、数组),有些是字面量(例如数字、字符串、布尔值和其他原语)。
【解决方案3】:

这是对按值传递和按引用传递 (Javascript) 的更多解释。 在这个概念中,他们谈论的是通过引用传递变量和通过引用传递变量。

按值传递(原始类型)

var a = 3;
var b = a;

console.log(a); // a = 3
console.log(b); // b = 3

a=4;
console.log(a); // a = 4
console.log(b); // b = 3
  • 适用于 JS 中的所有基本类型(字符串、数字、布尔值、未定义、空值)。
  • a 被分配了一个内存(比如 0x001),b 在内存中创建一个值的副本(比如 0x002)。
  • 因此更改变量的值不会影响另一个变量,因为它们都位于两个不同的位置。

通过引用传递(对象)

var c = { "name" : "john" };    
var d = c;

console.log(c); // { "name" : "john" }
console.log(d); // { "name" : "john" }

c.name = "doe"; 

console.log(c); // { "name" : "doe" }    
console.log(d); // { "name" : "doe" }
  • JS 引擎将对象分配给变量c,它指向一些内存,比如(0x012)
  • d=c时,在这一步中d指向同一个位置(0x012)。
  • 更改两个变量的任何更改值。
  • 函数就是对象

特殊情况,通过引用传递(对象)

c = {"name" : "jane"}; 
console.log(c); // { "name" : "jane" }    
console.log(d); // { "name" : "doe" }
  • equal(=) 运算符设置新的内存空间或地址

【讨论】:

    【解决方案4】:

    基本上,在 JavaScript 中,没有 Pass-By-Reference 的概念,因为 Pass-by-value 服务于使 JS 如此特别的目的。当我们在 JavaScript 中传递一个对象时, 1)函数需要带有值,并且该值是参考副本 2)这个值是原始对象的地址。

    【讨论】:

      【解决方案5】:

      我该如何处理这个问题?如果我想更改对象本身而不是其复制引用怎么办?

      我想在函数中重新分配一个对象,并且它的新值在调用函数中可见。

      为了增加公认的答案,并在那里解决 cmets 中未回答的问题,以下是我对通过参考传递的看法,并在实践中查看 scope / closure

      const obj = {
        count: 0,
      }
      
      function incrementReference(_obj) {
        obj.count++
      }
      
      function createIncrementByCopy(_obj) {
        let inner = {}
        Object.assign(inner, _obj)
      
        return function increment() {
          inner.count++
        }
      }
      
      function createScopedIncrement(_obj) {
        return function increment() {
          _obj.count++
        }
      }
      function createExtend(_obj) {
        return function increment(ext) {
          Object.assign(_obj, ext)
        }
      }
      
      console.log('obj', obj) // { count: 0 }
      
      incrementReference(obj)
      console.log('incrementReference ✅', obj.count) // 1
      
      const incrementCopy = createIncrementByCopy(obj)
      incrementCopy()
      console.log('incrementCopy ❌', obj.count) // 1
      
      const incrementA = createScopedIncrement(obj)
      incrementA()
      console.log('incrementA ✅', obj.count) // 2
      
      const extendObj = createExtend(obj)
      extendObj({ text: 'New Property!' })
      console.log('extendObj ✅', obj) // { count: 2, text: 'New Property!' } 

      下面的文章讨论了一个关于术语的常见混淆,我真的无话可说?https://dev.to/bytebodger/a-gotcha-of-javascript-s-pass-by-reference-1afm

      相关(良好的上下文,更复杂,不同的用例):https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#copying_accessors

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-02-23
        • 2012-05-30
        • 2018-10-16
        • 2017-05-20
        • 1970-01-01
        • 1970-01-01
        • 2011-12-15
        • 2016-04-11
        相关资源
        最近更新 更多