【问题标题】:JavaScript by reference vs. by value [duplicate]JavaScript 按引用与按值 [重复]
【发布时间】:2011-09-30 03:26:12
【问题描述】:

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

我做了很多搜索,找到了很多具体的例子(其中很多都在这里),我可以从中开始拼凑真正的规则,但我还没有找到一个,嗯描述这一切的书面文件。

此外,语言中是否有方法来控制是通过引用传递还是通过值传递?

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

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 总是按值传递。但是,如果将对象传递给函数,“值”实际上是对该对象的引用,因此函数可以修改该对象的属性但不会导致函数外部的变量指向其他对象 em>。

    一个例子:

    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. 数组和对象根据这两个条件作为引用传递或值传递。

      • 如果你用新的对象或数组改变那个对象或数组的值,那么它是按值传递的。

        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 - 这里的重点是向不成熟的开发人员解释,并说一切都是“按价值传递”,没有更多解释只是不够。它没有解释原语和数组如何传递或分配的区别。您可以争辩说它在技术上是正确的,但对于非成熟的开发人员来说,这是一个不充分的解释。您对“一旦您理解......”的评论表明,在您理解其他事情之前还不够 - 因此您不能只对新手说“一切都是按价值传递”并完成。
    猜你喜欢
    • 2015-10-14
    • 2014-09-10
    • 2013-10-27
    • 2014-02-09
    • 2013-12-02
    • 2019-05-07
    相关资源
    最近更新 更多