JavaScript按引用与按值

JavaScript按引用与按值,javascript,reference,pass-by-reference,pass-by-value,Javascript,Reference,Pass By Reference,Pass By Value,我正在寻找一些很好的综合性阅读材料,介绍JavaScript何时通过值传递某些内容,何时通过引用传递,何时修改传递的项影响函数外部的值,何时不影响。我还感兴趣的是,什么时候给另一个变量赋值是通过引用还是通过值,以及这是否遵循了与作为函数参数传递不同的规则 我已经做了很多搜索,找到了很多具体的例子(这里有很多),从中我可以开始拼凑出一些真正的规则,但我还没有找到一个完整的、写得很好的文档来描述这一切 另外,语言中是否有方法控制是通过引用还是通过值传递 下面是一些我想理解的问题。这些只是例子——我实

我正在寻找一些很好的综合性阅读材料,介绍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);
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
对于所有不同类型,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) {
   a = 3;
   b.push("foo");
   c.first = false;
}

var x = 4;
var y = ["eeny", "miny", "mo"];
var z = {first: true};
f(x,y,z);
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总是按值传递,但在数组或对象中,值是对它的引用,因此您可以“更改”内容

但是,我想你已经读过了;您拥有所需的文档:

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 = ...
  • 基本类型变量(如字符串、数字)始终作为pass传递 按价值计算
  • 基于这两个条件,数组和对象作为按引用传递或按值传递

    • 如果要使用新对象或数组更改该对象或数组的值,则该值为传递值

      object1={item:“car”};
      数组1=[1,2,3]

    在这里,您正在将新对象或数组指定给旧对象或数组。您没有更改属性的值 旧对象的。因此它是按值传递的

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

      object1.item=“汽车”;
      阵列1[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是正确的。它避免了这种混乱,并转向“高级”视图。您指的是什么“混乱”?对我来说,“通过值传递”是非常清楚的。
    更改变量的值永远不会更改基础原语或对象。但是,更改变量引用的对象的属性确实会更改基础对象。
    这两句话合在一起消除了许多疑问。非常感谢。来自c,这是愚蠢和恼人的,状态…
    var用户=[1,2,3,4];var x_用户=用户;x_用户推送(5)现在用户和x_用户是相同的,因为它是通过引用传递的。解决这个问题的一种方法是
    var x_users=users.slice(0);x_用户推送(6)现在用户和x_用户是不同的,因为x_用户不是指用户。我花了一段时间才弄明白:-)希望这可能会对某人有所帮助。虽然技术上是正确的,但我更愿意说JavaScript是。它避免了这种混乱,并转移到了“高级”视图。我做了一个小摆弄来处理这个问题:只需将上面的代码放在控制台中,然后看看……值发生了变化……关于调用Javascript做什么“按引用传递”,有一个由来已久的术语争论。我倾向于回避这一争论,并将JS对对象和数组的作用称为“通过指针传递”。数组和对象总是通过指针传递。如果修改传入的内容(访问指针),则会修改原始内容。如果将不同的数组或对象指定给指针变量,则不会修改原始数组或对象,因为您的变量现在“指向”不同的数组或对象。这在很大程度上是一场“术语辩论”,因为没有关于实际发生的事情的辩论。@newacct-对于那些喜欢声称“一切都是通过价值传递的”的人来说,这并不能帮助新手以任何方式理解这个问题,无论你认为自己在某种程度上在技术上多么正确。任何好的解释都必须解释对象和原语的传递方式之间的差异,以便新手理解实际使用中的差异,因为像这样的问答中的目标是一个清晰的解释,可以用于那些不了解更精细的实现细节或原语的技术含义的人条件。@jfriend00:问题是,“传球”没有什么特别的。它的工作方式与赋值或任何其他操作相同。一旦您了解到所有值都是原语或指向对象的指针,并且不将“对象”本身作为值来讨论,那么就不会有任何混淆。另外,JavaScript中传递和分配的语义与Java中的相同。“一切都是按值传递的”和Java在StackOverflow上的一般描述非常相似,并结合解释了所有非原语是如何被放置的