web-dev-qa-db-ja.com

参照による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);

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?
}

オブジェクトの完全に独立したコピーを作成したい場合(まったく参照がない場合)、それを実行するための最良の方法は何ですか?

346
jfriend00

私の理解するところでは、これは実際には非常に単純です。

  • Javascriptは always は値渡しですが、変数がオブジェクト(配列を含む)を参照する場合、 "value"はそのオブジェクトへの参照です。
  • 変数の値を変更すると、 決して 基礎となるプリミティブまたはオブジェクトが変更されることはありません。変数が新しいプリミティブまたはオブジェクトを指すだけです。
  • ただし、変数によって参照されるオブジェクトの property を変更すると、基礎となるオブジェクトも変更されます。

だから、あなたの例のいくつかを介して作業するには:

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"
594
nrabinowitz

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

はい、Javascriptは常に値で渡しますが、配列またはオブジェクトでは、値はそれを参照しているので、内容を「変更」できます。

しかし、私はあなたがすでにSOでそれを読んでいると思います。 ここ 欲しいドキュメントがあります:

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

  1. 文字列、数値のようなプリミティブ型変数は、常に値渡しとして渡されます。
  2. ArrayとObjectは、参照渡しまたはこれら2つの条件に基づく値渡しとして渡されます。

    • そのオブジェクトまたは配列の値を新しいオブジェクトまたは配列で変更している場合は、値で渡されます。

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

    ここでは、新しいオブジェクトまたは配列を古いオブジェクトに代入しています。古いオブジェクトのpropertyの値は変更していません。したがって、値渡しです。

    • オブジェクトまたは配列のプロパティ値を変更している場合は、参照渡しです。

      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
14
Mukund Kumar