ホームページ >ウェブフロントエンド >jsチュートリアル >javascript_javascript スキルで連続代入操作を使用することによって引き起こされる問題について説明します。

javascript_javascript スキルで連続代入操作を使用することによって引き起こされる問題について説明します。

WBOY
WBOYオリジナル
2016-05-16 15:29:361171ブラウズ

はしがき

記事のタイトルにあるこの文は、当初は海外の JavaScript 仕様で見られたものでしたが、最近になって JS の連続代入演算の特性 (落とし穴) が発見されるまで、十分な注目を集めませんでした。

オンラインで検索したところ、連続割り当ての非常に良い例を見つけました (ソース 1、ソース 2):

var a = {n:1};
a.x = a = {n:2};
console.log(a.x); // 输出?

答えは次のとおりです:

console.log(a.x); // undefined

あなたの答えが正しかったかどうかはわかりませんが、少なくとも私は間違っていました。

そこで、この機会を利用して、JS の連続代入がどのように機能するかを詳しく見ていきました

割り当て順序?

コード A=B=C; があるとします。代入ステートメントの実行順序は右から左であるため、問題は次のようになります。

推測 1: B = C; A = C ?

または、2: B = C; A = B と推測します。

2 つのオブジェクトが同時に 1 つのオブジェクトを指している場合、次のようにこのオブジェクトへの変更が同期されることは誰もが知っています。

var a={n:1};
var b=a;
a.n=2;
console.log(b);//Object {n: 2}
この機能に基づいて、連続した割り当ての順序をテストできます。

推測 1 に従って、C を特定のオブジェクトに置き換えると、1 行目と 2 行目のオブジェクトが実行されるときに 2 つの {n:1} が作成されるため、a の変更は b に同期されないことがわかります。例:

var b={n:1};
var a={n:1};
a.n=0;
console.log(b);//Object {n: 1}

推測 2 に従って、C を特定のオブジェクトに置き換えます。次のように、a と b は同時にオブジェクトを参照するため、a の変更が b に同期していることがわかります。

var b={n:1};
var a=b;
a.n=0;
console.log(b);//Object {n: 0}

真の連続割り当てのテスト:

var a,b;
a=b={n:1};
a.n=0;
console.log(b);//Object {n: 0}
推測 2 と一致していることがわかります。このテストが不正確だと感じる人がいる場合は、再度テストし、ECMA5 のセッター機能とゲッター機能を使用してテストできます。

まず、次のように、setter と getter は変数に実際に格納されているオブジェクトではなく、変数名に適用されます。

Object.defineProperty(window,"obj",{
 get:function(){
  console.log("getter!!!");
 }
});
var x=obj;
obj;//getter!!! undefined
x;//undefined
obj だけが「getter!!!」を出力しますが、x はこの機能を使用してテストしないことがわかります。
連続課題テスト 2:

Object.defineProperty(window,"obj",{
 get:function(){
  console.log("getter!!!");
 }
});
a=b=obj;//getter!!! undefined

getter を通じて再度確認すると、A=B=C では、C は 1 回だけ読み取られます。

したがって、連続代入の実際の演算規則は B = C; A = B; つまり、連続代入は常に等号の右側の式の結果のみを右から左に取り、それを左に代入します。等号の辺。

連続課題は別々に記述できますか?

上記から連続代入の実際のルールがわかります。次に、記事の冒頭のケースに戻ります。上記のルールに従って連続代入を分割すると、次のように結果が異なることがわかります。として:

つまり、連続代入文は右から左への代入の規則に従っていますが、それでも別の文で書くことはできません。なぜ
var a={n:1};
a={n:2};
a.x=a;
console.log(a.x);//Object {n: 2, x: Object}
なのかというと。
推測: 代入ステートメントの正確性を保証するために、js は代入ステートメントを実行する前に、まず割り当てられるすべての参照アドレスのコピーを取り出し、次に値を 1 つずつ代入します。

このコード a.x=a={n:2} のロジックは次のようになります。

1. 実行前に、a と a.x の a の参照アドレスが最初に取り出されます。この値は {n:1}

を指します。

2. メモリ内に新しいオブジェクト {n:2} を作成します

3. a={n:2} を実行し、a の参照を {n:1} を指すものから新しい {n:2} を指すものに変更します

4. a.x=a を実行します。この時点で、a はすでに新しいオブジェクトを指しており、a.x は実行前の元の参照を保持しているため、a.x の a は元の {n:1} オブジェクトを指しています。新しいオブジェクトが元のオブジェクトに与えられ、内容が {n:2} の属性 x が追加されます。これは a

になります。

5. ステートメントの実行が終了し、元のオブジェクトが {n:1} から {n:1,x:{n:2}} に変更され、元のオブジェクトは参照されなくなるため GC によってリサイクルされます。現在、新しいオブジェクト {n:2}

へのポイント

6. 記事の冒頭に実行結果があり、その後 a.x を実行すると、当然のことながら未定義になります

上記のプロセスをシリアル番号で示します:

上記のプロセスに従うと、古い a.x と新しい a は両方とも新しく作成されたオブジェクト {n:2} を指しているため、それらは一致していることがわかります。

テスト:

var b=a を追加したため、これは元のオブジェクトへの参照を追加することを意味するため、上記の手順 5 では解放されず、上記の結論が裏付けられます。

追記

今回を通して、記事のタイトルを振り返ると、継続課題の特徴が分かりました。

JS の内部メカニズムと考えられる結果をよく理解していない限り、JS の連続代入操作を使用しないようにしてください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。