【问题标题】:Javascript function not modifying array (reference?)Javascript函数不修改数组(参考?)
【发布时间】:2015-10-23 17:37:05
【问题描述】:

如果 JavaScript 将函数参数作为原始对象的引用传递,为什么我不能用这个简单的函数修改原始数组?

var array1 = ["one"];

function change(array) {
   var array2 = ["222"];
   array = array2;
}

change(array1);

console.log(array1); // this prints ["one"] instead of ["222"]

为什么有时对象似乎是作为引用传递的,而在这种情况下它是作为副本传递的?

【问题讨论】:

标签: javascript


【解决方案1】:

因为参数arrayarray1 不同。它们是单独的变量。请注意,变量是按值传递的,对于对象,它按值传递引用的副本。所以你需要这样做:

var array1 = ["one"];

array1 = change(array1);

function change(array) {
   var array2 = ["222"];
   array = array2;
   return array;  
}

console.log(array1);

【讨论】:

    【解决方案2】:

    为什么有时对象似乎是作为引用传递的,在这种情况下 它是作为副本传递的吗?

    它不是作为数组的副本传递的,而是作为对数组的引用的副本传递的。仍然只有一个数组,您可以使用该引用更改函数中的数组:

    var array1 = ["one"];
    
    function change(array) {
       array[0] = "222";
    }
    
    change(array1);
    
    console.log(array1); // this prints ["222"]
    

    你不能做的是在函数中用不同的数组替换数组。如果为参数分配一个新数组,那么它将指向新数组,但变量array1 仍然保持不变并指向原始数组。

    【讨论】:

    • 我会建议 OP 在他们的情况下执行此操作,因为他们不需要分配 array = array,请注意,如果 OP 想要对数组进行多次修改,则它的可扩展性不高有多个元素。
    • “你仍然可以修改传入的数组,它会改变数组本身,但是如果你分配给那个变量,那么它将不再改变数组”,很好的答案,谢谢!跨度>
    【解决方案3】:

    之所以你看到你所看到的,是因为 javascript 中的所有对象,数组都被认为是一个对象,都是通过引用传递的。当您初始化 array2 时,它会在内存中为该数组创建一个新位置,即一个新引用。然后在更改函数中,参数数组是对数组 1 的引用,但是当您将数组设置为等于数组 2 时,该变量的引用已更改为内存中的新位置,即数组 2 所在的位置。

    小提琴:http://jsfiddle.net/31s3LLjL/1/

    var array1 = ["one"];
    var array2 = ["one"];
    var array3 = ["one"];
    
    function change(array) {
       var array2 = ["222"];
       array = array2;
    }
    
    function change2(array) {
       array[0] = ["222"];
    }
    
    function change3(array) {
       var array2 = array;
       array2[0] = ["222"];
    }
    
    change(array1);
    change2(array2);
    change3(array3);
    
    console.log(array1); // prints one
    console.log(array2); // prints 222
    console.log(array3); // prints 222
    

    在第一个更改函数中,我们初始化了一个新数组(对象)。在其他两个更改函数中,我们只处理对内存中单个位置的相同引用。

    【讨论】:

      【解决方案4】:

      JavaScript 内存存储的工作方式是使用一组执行上下文。这些执行上下文中的每一个都有一个词法环境和一个变量环境。

      词法环境是来自所有父执行上下文的变量集,例如,保存在全局上下文中的变量将因此始终可用。

      变量环境是在当前执行上下文中声明的一组变量。这就是您在示例中更改的变量环境变量。

      function change(array) {
          var array2 = ["222"];
          array = array2;
      }
      

      在本例中,array 保存在变量环境中。然后,array2保存在变量环境中。正如你所看到的,这里的词法环境根本没有改变。因此,一旦函数中的执行完成,控制权返回,这个执行上下文就会失去作用域并且有资格进行垃圾回收,因为它与任何词法环境都没有联系。

      这就是为什么你使用的进程没有替换你传入的数组。你只是替换了本地范围内的一个值。

      你仍然可以修改传入的数组,它会改变数组本身,但如果你分配给那个变量,那么它将不再改变数组。

      【讨论】:

        【解决方案5】:

        问题是你确实有一个引用调用,但是在你的函数中改变了引用本身,而不是引用的值。

        你打算这样做:

        var array1 = ["one"];
        
        function change(array) {
           var value = "222";
           array[0] = value;
        }
        
        change(array1);
        
        console.log(array1); // this prints ["222"]
        

        更通用的方法是在函数内部使用一个新的 array2 并将该数组返回 (!) 给调用者。这当然不是原地改变数组,而是调用这样的函数时,只要将返回的值赋回原来的数组,就可以达到同样的效果。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-03-29
          • 2023-02-23
          • 2021-11-26
          • 2017-12-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多