我正在寻找一些很好的综合阅读材料,关于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总是按值传递,但是当一个变量引用一个对象(包括数组)时,“值”就是对该对象的引用。 改变变量的值不会改变底层的原语或对象,它只是将变量指向一个新的原语或对象。 但是,更改变量引用的对象的属性会更改底层对象。

那么,来看看你们的一些例子:

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总是按值传递,但是当一个变量引用一个对象(包括数组)时,“值”就是对该对象的引用。 改变变量的值不会改变底层的原语或对象,它只是将变量指向一个新的原语或对象。 但是,更改变量引用的对象的属性会更改底层对象。

那么,来看看你们的一些例子:

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"

Primitive type variable like string,number are always pass as pass by value. Array and Object is passed as pass by reference or pass by value based on these two condition. if you are changing value of that Object or array with new Object or Array then it is pass by Value. object1 = {item: "car"}; array1=[1,2,3]; here you are assigning new object or array to old one.you are not changing the value of property of old object.so it is pass by value. if you are changing a property value of an object or array then it is pass by Reference. object1.item= "car"; array1[0]=9; here you are changing a property value of old object.you are not assigning new object or array to old one.so it is pass by reference.

Code

    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总是通过值传递,但在数组或对象中,值是对它的引用,所以你可以“改变”内容。

但是,我想你们已经在SO上读过了;这里有你想要的文档:

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

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 = ...