7

次のモジュール構造が与えられます。

// module A:
export let a = 1; // named export
export function inc() { a++; } // named export

// module B:
let b = 1;
export default b; // default export (equivalent to `export default 1`)
export function inc() { b++; } // named export

// module C:
let c = {};
export default c; // default export

// module E:
import a, {inc as incA} from "./A";
import b, {inc as incB} from "./B";
import c from "./C";

incA();
console.log(a); // logs 2, because "a" has a live connection to the export value
a++; // Error (because a is a live read-only view on the export)

incB();
console.log(b); // logs 1, because "b" is disconnected from the export value
b++; // Does this throw an error as well?

c.prop = true; // I think mutations are always allowed, right?
c = {}; // but are reassignment allowed too?

export default b式 (または)のデフォルトのエクスポートがある場合export default 1、対応するインポートはこのエクスポート値から切断されます。これを考慮すると、そのようなインポートはまだ読み取り専用ですか、つまり、再割り当てできますac?

4

1 に答える 1

8

インポート バインディングは常に読み取り専用です。CreateImportBinding仕様の抽象操作のステップ 5 を参照してください。

  1. MN2をターゲット バインディングとして参照するNのenvRec不変の間接バインディングを作成し、バインディングが初期化されたことを記録します。

(私の強調)

その操作はModuleDeclarationInstantiation、モジュールのインポート エントリを処理するときに使用されます。

そう:

b++; // Does this throw an error as well?

はい、b読み取り専用です。

c.prop = true; // I think mutations are always allowed, right?

エクスポートされたオブジェクトで許可されていれば、はい。

c = {}; // but are reassignment allowed too?

いいえ、c読み取り専用です。


コメントで、あなたは次のように述べています。

しかし、ライブバインディングがなくなった場合、そのような変数を読み取り専用にすることは意味がありません

それらは変数ではなく、バインディングであることを覚えておくと便利です。変数はバインディングの一種ですが、すべてのバインディングが変数であるとは限りません (ES5 以前でも)。

問題がない場合に読み取り専用であることについては、2 つのバインディング レイヤーが関係していることに注意してください。

  1. ソース モジュールでのエクスポートのライブ バインディング。
  2. 消費モジュールでのインポートのライブ バインディング。

#1 の値が変更されないときに #2 を書き込み可能にするには、インポート メカニズムがそれを認識している必要がありますが、その情報はモジュールの exportsにはありません。エクスポートは、エクスポートされたバインディングの名前を与えるだけです。

さらに、不変のインポート バインディングだけでなく可変のインポート バインディングを使用することは、理解するのも実装するのも複雑です。(インポートされたバインディングを再割り当てすることも、スタイルの観点からすると混乱を招きます。)

それらがライブバインディングであるという事実は、インポートの値が変更される可能性があることを意味することを覚えておくことも重要です。推定:

mod1.js:

export let foo = 41;
export function incrementFoo() {
    ++foo;
};

mod2.js:

import { foo, incrementFoo } from "./mod1.js";
console.log(foo); // 41
incrementFoo();
console.log(foo); // 42 <== it changed

mod2.jsその特定のケースでは、( を呼び出すことによって) 変更を引き起こしたのはコードでしたincrementFooが、そうである必要はありません。mod1.js値を変更するために何らかの時間関連のイベントが発生したか、または他のモジュールによる への呼び出しの結果などが原因である可能性がありますmod1.js

しかし、はへのmod2.jsライブfooバインドであるため、変更が表示されます。mod1.jsfoomod2.js

于 2016-09-02T10:04:31.043 に答える