web-dev-qa-db-ja.com

JavaScriptコードの秘:: foo.xの価値

この問題は、GitHubのフロントエンドインタビューの質問集で発見しました。

_var foo = {n: 1};
var bar = foo;
foo.x = foo = {n: 2};
_

質問:foo.xの値は何ですか?

答えはundefinedです。

私はいくつかの研究を行ってきましたが、この問題が理解しているのは間違っています(間違っている場合は修正してください):

  • _var foo = {n: 1};_は、プロパティfooが1に等しいオブジェクトnを宣言します.
  • _var bar = foo;_は、barと同じオブジェクトを参照するオブジェクトfooを宣言します。
  • _foo.x = foo = {n: 2};_は、foo.x = (foo = {n: 2});と等しいと思います
  • そして、undefinedに等しい_foo.x_を取得しました。ただし、_bar.x_の値はオブジェクト_{n:2}_です。

barfooが同じオブジェクトを参照する場合、なぜ_bar.x_が値を取得したのに_foo.x_がundefinedであるのですか? _foo.x = foo = {n: 2};_で実際に何が起こっていますか?

52
AndyHu
foo.x = foo = {n: 2};

foo.x{n: 1}オブジェクトのプロパティxを参照し、{n: 2}fooに割り当て、foo{n: 2}{n: 1}オブジェクトのプロパティxへ。

重要なことは、fooが変更される前に、foo.xが参照するfooが決定されることです。

ES5仕様のセクション11.13.1 を参照してください:

  1. lrefLeftHandSideExpressionの評価結果とします。

  2. rrefAssignmentExpressionの評価結果とします。

代入演算子は右から左に関連付けられるため、次のようになります。

foo.x = (foo = {n: 2})

左側が右側の前に評価されます。

51
Ry-

foo.x = foo = {n:2};

ここで、fooは{n:1}代入前、つまりステートメントが実行される前のオブジェクトを指します。

ステートメントはfoo.x =(foo = {n:2});のように書き換えることができます

オブジェクトの用語では、上記のステートメントは{n:1} .x =({n:1} = {n:2});のように書き直すことができます

割り当ては右から左にのみ行われるため。したがって、ここでは、fooが実行を開始する前にどのオブジェクトを参照しているかを確認する必要があります。

R.H.Sの解法:foo = {n:2}; foo{n:2}を参照しています。

残っている問題に戻って、

foo.x = foo;

L.H.Sのfoo.xはまだ{n:1} .xであるのに対し、R.H.Sのfoo.xは{n:2}です。

そのため、このステートメントが実行された後、{n:1}{n:1、x:{n:2}}になりますが、barはまだそれを参照しています。 foo{n:2}を指すようになりました。

Fooには{n:2}の値が1つしかないため、実行時にfoo.xはundefinedを返します。

しかし、bar.xを実行しようとすると、{n:2}が得られます。または、単にbarを実行すると、結果は

オブジェクト{n:1、x:Object}

23

私は別の、私が見つけたもの、これについての便利な考え方を追加すると思いました。

これらの変数はメモリ内の同じものへの単なる参照であるため、これらの最後の変数の割り当てはbar.x = foo = {n:2};の記述と同等です。

つまり、foobarは、最初は両方とも同じオブジェクト{n:1}を参照しています。 foo.x =を使用する場合、{n:1}にアクセスし、xプロパティを追加します。これは、barまたはfooのいずれかで実行できます。これらは両方ともメモリ内の同じオブジェクトを指しているからです!違いはありません。

次に、その行foo.x = foo = {n:2}を完了すると、オブジェクトリテラル構文を使用してメモリ内に別のbrandオブジェクトを作成し、fooをポイントに設定します。 tothatオブジェクト、{n:2}、現在の{n:1, x: {n: 2}の代わりに。ただし、これはfooプロパティを追加したときにxが指すものには影響しません。

これはかなり紛らわしいですが、変数はメモリ内の場所/オブジェクトへの単なるポインターであり、オブジェクトリテラル構文は以前の既存のオブジェクトを変更していないという事実について考えるのは理にかなっていると思います(たとえ似ていても)。新しいものを作成しています。

この質問 への受け入れられた回答の始まりも役立つかもしれません。

4
Zach Nagatani

オブジェクト変数はJavaScript内のオブジェクトへの単なる参照であり、オブジェクト自体ではないことを理解してください。

var foo = {n: 1}-> fooは実オブジェクト{n:1}を参照しますvar bar = foo-> barは実オブジェクト{n:1}への参照にもなりました

トリッキーな部分はもちろん3行目です:foo.x = foo = {n: 2}

これは次と同等です:(reference to {n: 1}).x = (foo = {n: 2})->この行が完全に評価された後、fooは新しいオブジェクト{n:2}への参照になります。ただし、fooは行の評価前に元のオブジェクト{n: 1}を参照するため、行が評価された後、元のオブジェクト{n: 1}{n: 1, x: [reference to]{n: 2}}になり、変更されたオブジェクトは参照bar。参照バーがない場合、元のオブジェクトは破棄されます

3
Hou

私が表現を理解するように:

foo.x = foo = {n: 2};

次とまったく同じです。

foo.x = {n: 2} ; 
foo = {n: 2};

そしてこの後、次のことが明らかになりました:

 bar=={n: 1, x: {n:2}};
 foo=={n:2};
 foo.x==undefined
3
Ron Lavit