Javascript引用与价值

jfr*_*d00 367 javascript reference pass-by-reference pass-by-value

我正在寻找一些很好的综合阅读材料,当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);
Run Code Online (Sandbox Code Playgroud)

对于所有不同类型,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?
}
Run Code Online (Sandbox Code Playgroud)

如果我想制作一个完全独立的对象副本(没有任何参考),那么最佳实践方法是什么?

nra*_*itz 626

我的理解是,这实际上非常简单:

  • Javascript 总是按值传递,但是当变量引用对象(包括数组)时,"value"是对象的引用.
  • 更改变量的值永远不会更改基础基元或对象,它只是将变量指向新的基元或对象.
  • 但是,更改变量引用的对象的属性会更改基础对象.

因此,要完成一些示例:

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
Run Code Online (Sandbox Code Playgroud)

例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"
Run Code Online (Sandbox Code Playgroud)

  • 虽然技术上是正确的,但我更喜欢说JavaScript是[通过对象共享](http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing).它避免了这种混乱并转向"高级"观点. (64认同)
  • `更改变量的值永远不会更改基础原语或对象.但是,更改变量引用的对象的属性确实会更改基础对象.这两个句子放在一起消除了很多疑点.谢谢! (29认同)
  • 你指的是什么"混乱"?对我来说,"按价值传递"非常清楚. (10认同)
  • 来自c,这是一个愚蠢而烦人的州州...... (7认同)
  • ```var users = [1,2,3,4]; var x_users = users; x_users.push(5);```现在用户和x_users是相同的,因为它是通过引用传递的.解决这个问题的一种方法是```var x_users = users.slice(0); x_users.push(6);```现在用户和x_users是不同的,因为x_users不是指用户.我花了一段时间才弄清楚:-)希望这可能对某人有所帮助. (4认同)
  • @pst - 这是有道理的,但请注意引用的维基百科页面中提出的问题 - 大多数人不使用该术语,而(大型)Java社区称之为"按值传递".不过,我同意这有点令人困惑. (2认同)

nnn*_*nnn 54

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

一个例子:

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 = ...
Run Code Online (Sandbox Code Playgroud)

  • `Array`是一个对象所以也会改变. (5认同)
  • @Hritik - 除了所有不是对象的原始值。 (2认同)

Edg*_*ado 27

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

但是,我认为你已经在SO上阅读了它; 在这里你有你想要的文件:

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

  • 虽然技术上是正确的,但我更喜欢说JavaScript是[通过对象共享](http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing).它避免了这种混乱并转向"高级"观点. (2认同)

Muk*_*mar 16

  1. 像string,number这样的原始类型变量总是作为pass by value传递.
  2. Array和Object作为传递引用传递,或者根据这两个条件传递值.

    • 如果要使用新的Object或Array更改该Object或数组的值,则它将通过Value传递.

      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
Run Code Online (Sandbox Code Playgroud)

  • 有一个关于调用Javascript"通过引用传递"的术语辩论.我更倾向于支持辩论并调用JS为对象和数组"传递指针"所做的事情.数组和对象总是通过指针传递.如果修改传入的内容(访问指针),则会修改原始内容.如果为指针变量分配不同的数组或对象,则不会修改原始数据,因为您的变量现在"指向"不同的数组或对象.其中大部分是"术语辩论",因为没有关于实际发生的事情的辩论. (12认同)
  • @newacct - 对于那些喜欢声称"一切都是通过价值传递"的人来说,这无助于新手以任何方式理解这个问题,无论你认为自己在某种程度上是多么技术正确.任何好的解释都必须解释对象和基元如何通过之间的区别,以便新手理解实际使用中的差异,因为这样的问答中的目标是一个明确的解释,可以用于那些不喜欢的人.了解更精细的实施细节或术语的技术含义. (10认同)
  • @newacct - 这里的重点是向那些不是老练的开发人员解释并说一切都是"按价值传递"而没有更多解释只是仅仅是不够.它没有解释原语和数组如何传递或分配的区别.您可以认为它在技术上是正确的,但对于非复杂的开发人员来说,这是一个不充分的解释.你的评论"一旦你理解......"就表明,只有你了解其他事情才足够 - 因此你不能只是说"一切都是通过价值传递"给新手并完成. (7认同)
  • @jfriend00:问题是,"传球"并没有什么特别之处.它的工作方式与分配或任何其他操作相同.一旦你理解了所有的值都是基元或指向对象的指针,而不是将"对象"称为值本身,那么就没有混淆.此外,JavaScript中传递和分配的语义与Java中的语义相同.并且"一切都是通过价值传递"几乎就是如何在StackOverflow上描述Java,并结合解释所有非基元是如何指向对象的. (4认同)
  • 只需将上面的代码放在你的控制台中,看看...值得到改变.. (2认同)