web-dev-qa-db-ja.com

変数を別の変数と等しく設定する

JavaScriptで変数を別の変数と等しく設定することについていくつか質問があります。

オブジェクトaを作成し、b = aを設定するとします。

var a = {
  fname: "Jon",
  lname: "Smith",
  age: 50
}

var b = a;

aのプロパティを変更すると、bも変更されることを理解しています。これは、b = aを設定すると、aのデータを複製せず、aのデータへの参照を作成するためです。たとえば、a.fname = "Sarah"を設定した場合、b.fnameの新しい値は"Sarah"になります。

a = {}を設定してaを「クリア」しようとすると、オブジェクトbは変更されません。この方法でオブジェクトを操作すると、最初の例とは異なる結果が生成される理由がわかりません。


また、次のシナリオについて質問があります。

var x = 10;
var z = x;

次にx = 20を設定すると、zの値は変更されません。最初の質問で説明した動作に基づいて、zの新しい値はxの新しい値を反映すると思います。私がここで欠けているものを誰かが説明してくれませんか?

ありがとうございました!

6
KGraber

両方の質問に対する本当に短い答えは、ある変数を別の変数と等しくすると、最初の変数の内容のコピーが作成され、2番目の変数に格納されるということです- 2つの変数間のリンケージはありません。

しかし、詳細と、場合によってはリンクがあるように見える理由については、以下をお読みください...


JavaScriptは、多くの言語と同様に、データを2つの広いカテゴリーに分類します。値のタイプと参照タイプです。 JavaScriptの値のタイプはそのプリミティブです。

  • ストリング
  • ブール
  • ヌル
  • undefined
  • symbol

これらのタイプのいずれかを変数に割り当てると、実際のデータはその変数に格納されます。ある変数を別の変数に等しく設定すると、コピー(リンケージではない)のプリミティブが作成され、新しい変数に格納されます。

var a = 10;  // Store the actual number 10 in the a variable
var b = a;   // Store a COPY of the actual number stored in a (10) in the b variable
a = 50;      // Change the actual data stored in a to 50 (no change to b here)
console.log(b);  // 10

参照タイプを使用すると、少し異なることが起こります。変数を参照型に割り当てると、変数は、実際のオブジェクト自体ではなく、オブジェクトが実際に格納されているメモリ位置への参照のみを保持します。したがって、これを行うと:

var a = {foo:"bar"};

aは実際にはオブジェクト自体を格納しません。オブジェクトが見つかる場所(0x3C41Aなど)のメモリ位置のみを格納します。

ただし、別の変数を最初の変数と同じように設定する限り、プリミティブの場合と同様に機能します--acopy最初の変数の内容が作成され、2番目の変数に渡されます。

次に例を示します。

// An object is instantiated in memory and a is given the address of it (for example 0x3C41A)
var a = {}; 
 
// The contents of a (the memory location of an object) is COPIED into b.
// Now, both a and b hold the same memory location of the object (0x3C41A)
var b = a;

// Regardless of whether a or b is used, the same underlying object
// will be affected:
a.foo = "test";
console.log(b.foo); // "test"

// If one of the variables takes on a new value, it won't change
// what the other variable holds:
a = "something else";
console.log(b);   // The object stored in memory location (0x3C41A)

したがって、最初のテストでは、1つのオブジェクトにアクセスする方法が2つあり、aが保持しているもの(オブジェクトのメモリの場所)を別のオブジェクトに変更するだけなので、1つしかありません。 bを介して、元のオブジェクトにアクセスするための残りの方法。


aを「クリア」しようとすると、a = {}、オブジェクトbは変更されません。この方法でオブジェクトを操作すると、最初の例とは異なる結果が生成される理由がわかりません。

これでa = {}はオブジェクトをクリアしていません。 aが別の場所を指しているだけです。

7
Scott Marcus

説明してみましょう:

1)例では、abは同じオブジェクトへの参照ですが、a.fname(またはb.fname)はそのオブジェクトの属性です。したがって、属性を操作すると、オブジェクト内で変更されますが、参照は影響を受けませんが、同じオブジェクトを参照しているため、オブジェクト自体が変更されています。一方、a = {}は、オブジェクト自体またはbへの参照に影響を与えることなく、オブジェクトへの参照を置き換えるだけです。
新しい空のオブジェクトへの新しい参照を作成しただけで、クリアランスはありません。

2)これらはオブジェクトではないため、値を直接操作している参照はありません。これは、厳密な型の操作に慣れていない場合、特に最初は混乱する可能性のあるオブジェクトとプリミティブの間に違いがあるためです。

2
Chaz

あなたの最初のケースでは:

var a = {
  fname: "Jon",
  lname: "Smith",
  age: 50
}

var b = a;
a = {}

bはバックグラウンドで発生する一連のイベントであるため、変更されません。

  • メモリアドレス0x1234にデータを含むオブジェクトを作成します

    fname: "Jon",lname: "Smith",age: 50

  • そのメモリブロックへのポインタは、aに格納されます。

  • 次に、そのポインタがbにコピーされます

この時点で、メモリの同じビットへの2つの参照があります。そのメモリブロック内の何かを変更すると、そのブロックへの両方の参照に影響します。

  • a = {}はメモリブロック0x1234をクリアしませんが、別のメモリロケーション(0x1235)に新しいオブジェクトを作成し、そのブロックへのポインタをaに格納します。 bがまだ指しているため、0x1234のメモリは変更されません。

この種のメモリ管理には、単純な変数とオブジェクト/ポインタの間で違いがあります。文字列と数値はさまざまな種類があり、オブジェクトの「参照渡し」とは対照的に「値渡し」です。

1
steenbergh