【问题标题】:JavaScript by reference vs. by value [duplicate]JavaScript 通过引用与通过值 [重复]
【发布时间】:2022-11-26 07:16:45
【问题描述】:

我正在寻找一些很好的综合阅读材料,了解 JavaScript 何时按值传递某些内容,何时按引用传递以及修改传递的项目何时影响函数外部的值以及何时不影响。我还对通过引用还是通过值分配给另一个变量感兴趣,以及它是否遵循与作为函数参数传递不同的规则。

我已经做了很多搜索并找到了很多具体的例子(其中很多都在 SO 上),我可以从中开始拼凑出真正的规则,但我还没有找到一个写得很好的文件描述了这一切。

此外,语言中是否有方法可以控制某些内容是按引用还是按值传递?

以下是我想了解的一些问题类型。这些只是例子——我实际上是想了解语言所遵循的规则,而不仅仅是特定例子的答案。但是,这里有一些例子:

function f(a,b,c) {
   a = 3;
   b.push("foo");
   c.first = false;
}

var x = 4;
var y = ["eeny", "miny", "mo"];
var z = {first: true};
f(x,y,z);

对于所有不同类型,什么时候 x、y 和 z 的内容在 f 的范围之外发生变化?

function f() {
    var a = ["1", "2", "3"];
    var b = a[1];
    a[1] = "4";
    // what is the value of b now for all possible data types that the array in "a" might hold?
}

function f() {
    var a = [{yellow: "blue"}, {red: "cyan"}, {green: "magenta"}];
    var b = a[1];
    a[1].red = "tan";
    // what is the value of b now and why?
    b.red = "black";
    // did the value of a[1].red change when I assigned to b.red?
}

如果我想制作一个完全独立的对象副本(没有任何引用),最好的做法是什么?

【问题讨论】:

    标签: javascript reference pass-by-reference pass-by-value


    【解决方案1】:

    我的理解是,这其实很简单:

    • Javascript 是总是按值传递,但当变量引用对象(包括数组)时,“值”是对该对象的引用。
    • 改变变量的值绝不更改底层原语或对象,它只是将变量指向新的原语或对象。
    • 但是,改变一个财产变量引用的对象的变化确实改变了底层对象。

    因此,要完成一些示例:

    function f(a,b,c) {
        // Argument a is re-assigned to a new value.
        // The object or primitive referenced by the original a is unchanged.
        a = 3;
        // Calling b.push changes its properties - it adds
        // a new property b[b.length] with the value "foo".
        // So the object referenced by b has been changed.
        b.push("foo");
        // The "first" property of argument c has been changed.
        // So the object referenced by c has been changed (unless c is a primitive)
        c.first = false;
    }
    
    var x = 4;
    var y = ["eeny", "miny", "mo"];
    var z = {first: true};
    f(x,y,z);
    console.log(x, y, z.first); // 4, ["eeny", "miny", "mo", "foo"], false
    

    示例 2:

    var a = ["1", "2", {foo:"bar"}];
    var b = a[1]; // b is now "2";
    var c = a[2]; // c now references {foo:"bar"}
    a[1] = "4";   // a is now ["1", "4", {foo:"bar"}]; b still has the value
                  // it had at the time of assignment
    a[2] = "5";   // a is now ["1", "4", "5"]; c still has the value
                  // it had at the time of assignment, i.e. a reference to
                  // the object {foo:"bar"}
    console.log(b, c.foo); // "2" "bar"
    

    【讨论】:

    • 虽然在技术上是正确的,但我更愿意说 JavaScript 是 Pass By Object Sharing。它避免了这种混淆并转向了“高层次”视图。
    • 你指的是什么“混乱”?对我来说,“按价值传递”是非常清楚的。
    • Changing the value of a variable never changes the underlying primitive or object. However, changing a property of an object referenced by a variable does change the underlying object.这两句话放在一起就解开了很多疑惑。谢谢!
    • 来自 c,这是愚蠢和烦人的,state state state ...
    • var users = [1,2,3,4]; var x_users = users; x_users.push(5); 现在 users 和 x_users 是相同的,因为它是通过引用传递的。解决此问题的一种方法是 var x_users = users.slice(0); x_users.push(6); 现在 users 和 x_users 不同,因为 x_users 不是指用户。花了我一段时间才弄明白 :-) 希望这可以帮助别人。
    【解决方案2】:

    Javascript总是按值传递。但是,如果将对象传递给函数,“值”实际上是对该对象的引用,因此该函数可以修改该对象的属性但不会导致函数外的变量指向其他对象.

    一个例子:

    function changeParam(x, y, z) {
      x = 3;
      y = "new string";
      z["key2"] = "new";
      z["key3"] = "newer";
    
      z = {"new" : "object"};
    }
    
    var a = 1,
        b = "something",
        c = {"key1" : "whatever", "key2" : "original value"};
    
    changeParam(a, b, c);
    
    // at this point a is still 1
    // b is still "something"
    // c still points to the same object but its properties have been updated
    // so it is now {"key1" : "whatever", "key2" : "new", "key3" : "newer"}
    // c definitely doesn't point to the new object created as the last line
    // of the function with z = ...
    

    【讨论】:

    • Array 是一个对象,所以也会改变。
    • 除了 JavaScript 中的几乎所有东西都是对象。
    • @Hritik - 除了所有不是对象的原始值。
    【解决方案3】:

    是的,Javascript 总是按值传递,但在数组或对象中,值是对它的引用,因此您可以“更改”内容。

    但是,我认为您已经在 SO 上阅读过它; here 你有你想要的文档:

    http://snook.ca/archives/javascript/javascript_pass

    【讨论】:

    【解决方案4】:
    1. 像字符串、数字这样的原始类型变量总是传递为传递 按价值。
    2. Array 和 Object 根据这两个条件按引用传递或按值传递。

      • 如果您正在使用新对象或数组更改该对象或数组的值,则它是按值传递的。

        object1 = {item: "car"}; array1=[1,2,3];

      在这里,您正在将新对象或数组分配给旧对象。您没有更改属性的值 旧对象。所以它是按值传递的。

      • 如果您要更改对象或数组的属性值,则它是通过引用传递的。

        object1.item= "car"; array1[0]=9;

      在这里您正在更改旧对象的属性值。您没有将新对象或数组分配给旧对象。因此它是通过引用传递的。

      代码

          function passVar(object1, object2, number1) {
      
              object1.key1= "laptop";
              object2 = {
                  key2: "computer"
              };
              number1 = number1 + 1;
          }
      
          var object1 = {
              key1: "car"
          };
          var object2 = {
              key2: "bike"
          };
          var number1 = 10;
      
          passVar(object1, object2, number1);
          console.log(object1.key1);
          console.log(object2.key2);
          console.log(number1);
      
      Output: -
          laptop
          bike
          10
      

    【讨论】:

    • 只需将上面的代码放在您的控制台中,然后查看...值发生了变化..
    • 关于将 Javascript 所做的称为“通过引用传递”,有一个由来已久的术语辩论。我宁愿回避争论,将 JS 对对象和数组的作用称为“通过指针传递”。数组和对象总是通过指针传递。如果您修改传入的内容(访问指针),则会修改原始内容。如果您将不同的数组或对象分配给指针变量,则原始变量不会被修改,因为您的变量现在“指向”不同的数组或对象。这在很大程度上是一场“术语辩论”,因为没有关于实际发生的事情的辩论。
    • @newacct - 对于那些喜欢声称“一切都是按价值传递”的人来说,这无助于新手以任何方式理解这个问题,无论您认为自己在某种程度上在技术上多么正确。任何好的解释都必须解释对象和基元的传递方式之间的区别,这样新手才能理解实际使用中的区别,因为像这样的问答的目标是一个清晰的解释,可以为那些不知道的人使用不了解更精细的实施细节或术语的技术含义。
    • @jfriend00:事实是,“通过”并没有什么特别之处。它的工作方式与分配或任何其他操作相同。一旦您了解所有值都是原始值或指向对象的指针,而不是将“对象”本身作为值来谈论,那么就不会有混淆。此外,JavaScript 中传递和分配的语义与 Java 中的相同。 StackOverflow 上对 Java 的描述几乎就是“一切都按值传递”,并解释了所有非基元都是指向对象的指针。
    • @newacct - 这里的重点是向那些不是老练的开发人员的人解释,并说一切都是“按价值传递”而没有更多的解释是不够的。它没有解释原语和数组如何传递或分配的区别。您可以争辩说它在技术上是正确的,但对于非老练的开发人员来说,这是一个不充分的解释。你的评论“一旦你理解了......”表明在你理解其他事情之前它是不够的 - 因此你不能只对新手说“一切都是按价值传递”并完成。
    猜你喜欢
    • 1970-01-01
    • 2017-06-14
    • 2019-03-21
    • 2013-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-27
    • 2012-06-03
    相关资源
    最近更新 更多