8

Chrome コンソールで遊んでいて、理解できないことに気づきました。JS では、変数は値によってコピーされ、オブジェクトは参照によってコピーされることを知っています。以下のコードは期待どおりに動作し、2 を出力し、JS オブジェクトが参照として機能することを証明します。

var objA = {a: 1};
var objB = objA;
objA.a = 2; 
objB.a; // 2

ただし、このコードは正常に機能しません。objBa.a が出力されることを期待して2いましたが、1代わりに出力されます。なんで?

var objA = {a: 1};
var objB = objA;
objA = {a: 2};  //Assigned whole object here instead property.
objB.a; //1 - Shouldn't this be 2 ??
4

5 に答える 5

13

オブジェクトを持つ変数は、参照ではなく、オブジェクトへのポインター(C ポインターなど)と考えたいと思います。

3 行目では、 を置き換えてobjA、別のオブジェクトを「指す」ようにしています。「指差し」であっても変わりません。objB

3 行目で、objA今は を指していますが、2 行目で に割り当てたときに指していたもの{a:2}objBまだ指しています。objAobjB{a:1}

line 1: objA -> {a:1}
line 2: objA -> {a:1} <- objB
line 3: objA -> {a:2}, objB -> {a:1}
于 2013-10-18T11:33:52.327 に答える
6

私は JavaScript 変数を付箋のように考えています。付箋は、冷蔵庫に貼る小さなメモです。付箋に何が書ける?小さな情報を書き込むことができます。

JavaScript には、プリミティブ値と参照値の 2 種類の情報があります。プリミティブ値は、付箋に直接書き込むことができる小さな情報です。それらには以下が含まれます:

  1. ブール値
  2. 数字
  3. ストリングス
  4. ヌル
  5. 未定義

一方、参考値は小さな付箋に書ききれないほどの情報量です。では、参照値を付箋に保存するにはどうすればよいでしょうか。

あなたはそうしない。

参照値 (配列、オブジェクト、関数など) は大きな紙に書かれ、それらへの参照のみが付箋に書かれます。たとえば、妻は次のように書いています。

ハニー、食料品のリストはキーボードの下にあります。

ここで、食料品のリストは配列です (つまり、大量の情報)。小さな付箋に書くことはできないので、大きな紙に書いて、どこにあるかを示す付箋を作るだけです. プログラミング用語では:

var groceryList = ["1 apple", "2 bananas", "3 loaves of bread"];

ここでは、実際の食料品リストがメモリのどこかに保存され、食料品リストのアドレスのみが変数に保存されますgroceryList


では、ある変数を別の変数に代入するとどうなるでしょうか? まず、プリミティブ値の例を見てみましょう。

var x = 2;
var y = x;
alert(y);  // 2
y = 3;
alert(x);  // 2

これが起こっていることです:

  1. 2新しい付箋に番号を書いて、冷蔵庫に貼ります。
  2. 2番号を付箋xから別の付箋にコピーしyて、冷蔵庫に貼り付けます。
  3. 付箋の値を消去し、代わりにy番号を書き込みます。3
  4. 現在、付箋の値は であり、付箋xはです。2y3

xこれは、付箋の値を付箋にコピーしているだけなので、値によるコピーと呼ばれますy

次に、参照によるコピーの例を見てみましょう。実際、参照によるコピーの例を見てみましょう:

var objA = {a: 1};
var objB = objA;
objA.a = 2;
objB.a; // 2

あなたの例で起こっていることは次のとおりです。

  1. メモリのどこかにオブジェクトを作成し、{a: 1}このオブジェクトのアドレスを付箋に書きobjAます。x簡単にするために、このアドレスを呼びましょう。
  2. x付箋objAから別の付箋に住所をコピーしますobjB。と の両方が、メモリ ロケーション に保存されている同じオブジェクトobjAを参照するようになりました。objB{a: 1}x
  3. したがって、変更するobjA.aと同じ変更の値が反映されます。これは、との両方がメモリ ロケーション に保存されている同じオブジェクトを参照するobjB.aためです。objAobjBx

オブジェクトの参照を付箋から付箋に単純にコピーしているため、これは参照によるコピーと呼ばれobjAますobjB。実際のオブジェクトをコピーしているわけではありません。

では、参照によるコピーと値によるコピーの違いは何でしょうか? 何もない。どちらの場合も、ある付箋の値を別の付箋にコピーしているだけです。

2 つの付箋は、まったく同じ情報が含まれている場合にのみ、同等であると言われます。たとえば、以下は同等です。

var x = 2;
var y = 2;
alert(x === y); // true

var o = {a: 1};
var p = o;
alert(o === p); // true

ただし、次の値は同等ではありません。

var o = {a: 1};
var p = {a: 1};
alert(o === p); // false

それらが等しくない理由は、別のメモリ ロケーション say に格納されているオブジェクトを指しているのに対しo、メモリ ロケーション sayに格納されているオブジェクトを指すためです。これらのオブジェクトはどちらもまったく同じプロパティを持っていますが、実際には 2 つの異なるオブジェクトです。xpy

たとえば、任天堂のゲームボーイは、見た目がどれだけ同じでも、同じものは 2 つとありません。同じ精神で、最後の例を見てみましょう。

var objA = {a: 1};
var objB = objA;
objA = {a: 2};  //Assigned whole object here instead property.
objB.a; //1 - Shouldn't this be 2 ??

上記のコードで何が起こっているかを次に示します。

  1. {a: 1}メモリの場所にオブジェクトを作成しx、アドレスxを付箋に書きobjAます。
  2. xアドレスを付箋から付箋objAにコピーしますobjB。どちらも現在、メモリ ロケーション に保存されている同じオブジェクトを指していますx
  3. {a: 2}メモリの場所に新しいオブジェクトを作成しy、アドレスyを棒のメモに書き込みますobjA。現在objAは参照値があり、参照値yがありobjBますx。これらは 2 つの異なるオブジェクトを参照します。

ご覧のとおり、新しい参照値を に割り当てると、objA単に古い参照値が上書きされます。{a: 1}objectをobject に置き換えません{a: 2}。これは JavaScript では不可能です。

于 2013-10-18T12:20:29.023 に答える
2

最初の例は、両方の変数が指すオブジェクトが同じであるため機能します。

2 番目の例では、別のオブジェクトobjAat に割り当てているため、そうではありませんline #3

objA = {a: 2};  //Assigned whole object here instead property.

これobjAにより、別のオブジェクト ( {a:2})objBが指し示されますが、 は古いオブジェクトを指します。

于 2013-10-18T11:33:58.950 に答える
1

あなたの場合の ObjB は、変数 objA を指しているのではなく、変数 objA が指しているオブジェクトを指しているため、オブジェクトのプロパティを変更することは、変数が指す場所を変更することと同じではありません。

JavaScript では、値渡しされる変数があります。オブジェクトに関しては、何も違いはありません。変数は、たとえばC++と同じようにオブジェクトへのポインターではありません。javascript 自体によってのみアクセス可能なポインターへの参照のみが含まれています。だからあなたがするとき:

objA = objB

メモリ内のオブジェクトへの参照ポインタのみをコピーします。

于 2013-10-18T11:37:46.317 に答える