JavaScriptでは、var
宣言はグローバルオブジェクトにプロパティを作成します。
var x = 15;
console.log(window.x); // logs 15 in browser
console.log(global.x); // logs 15 in Node.js
ES6では、ブロックスコープを持つ let
宣言を使用した字句スコープが導入されています。
let x = 15;
{
let x = 14;
}
console.log(x); // logs 15;
ただし、これらの宣言はグローバルオブジェクトにプロパティを作成しますか?
let x = 15;
// what is this supposed to log in the browser according to ES6?
console.log(window.x); // 15 in Firefox
console.log(global.x); // undefined in Node.js with flag
let
ステートメントはグローバルオブジェクトにプロパティを作成しますか?
spec によると、いいえ:
グローバル環境レコードは論理的には単一のレコードですが、 オブジェクト環境レコード と 宣言型環境レコード をカプセル化する複合として指定されます。 オブジェクト環境レコード は、そのベースオブジェクトとして、関連付けられた レルム のグローバルオブジェクトを持っています。このグローバルオブジェクトは、グローバル環境レコードの
GetThisBinding
具象メソッドによって返される値です。グローバル環境レコードのオブジェクト環境レコードコンポーネントには、すべての組み込みグローバルのバインディング( 18節 )と、FunctionDeclaration、GeneratorDeclarationによって導入されたすべてのバインディングが含まれます。、またはVariableStatementグローバルコードに含まれています。 グローバルコード内の他のすべてのECMAScript宣言のバインディングは、グローバル環境レコードの 宣言型環境レコード コンポーネントに含まれています。
もう少し説明:
declarative環境レコードは、バインディングを内部データ構造に格納します。そのデータ構造を取得することは決して不可能です(関数スコープについて考えてください)。
object環境レコードは、実際のJSオブジェクトをデータ構造として使用します。オブジェクトのすべてのプロパティがバインディングになり、その逆も同様です。グローバル環境には、「バインディングオブジェクト」がグローバルオブジェクトであるオブジェクト環境オブジェクトがあります。別の例はwith
です。
さて、引用された部分が述べているように、FunctionDeclaration s、GeneratorDeclaration s、およびVariableStatement sだけが、グローバル環境のobject環境レコード。つまりこのバインディングのみがグローバルオブジェクトのプロパティになります。
他のすべての宣言(例:const
およびlet
)は、グローバル環境のdeclarative環境レコードに格納されます。グローバルオブジェクトに基づいています。
let
変数とvar
変数はどちらも、スクリプトのトップレベルで宣言されている場合、スクリプトファイルの外部からアクセスできます。ただし、var
変数のみがwindow
オブジェクトに割り当てられます。証拠としてこのコードスニペットを見てください:
<script>
var namedWithVar = "with var";
let namedWithLet = "with let";
</script>
<script>
console.log("Accessed directly:");
console.log(namedWithVar); // prints: with var
console.log(namedWithLet); // prints: with let
console.log("");
console.log("Accessed through window:");
console.log(window.namedWithVar); // prints: with var
console.log(window.namedWithLet); // prints: undefined
</script>
仕様による :
「let宣言とconst宣言は、実行中の実行コンテキストのLexicalEnvironmentにスコープされる変数を定義します。」
これは、実行スコープの内側では変数にアクセスできるはずですが、外側ではアクセスできないことを意味します。これにより、実行範囲が、関数のみまたはグローバルの従来のJSクロージャ構造を超えて拡張されます。
let
変数をグローバルに定義すると、Firefoxで見られるように、グローバル変数がバインドされますが、V8/iojsはバインドされません。
console.log(typeof x)
がiojsでnumber
をreturlすることは言及する価値があります。実際には、モジュールや関数の外部で変数を定義するべきではありません...特にconst
とlet
では
letを使用すると、スコープが使用されるブロック、ステートメント、または式に限定された変数を宣言できます。これは、ブロックスコープに関係なく、変数をグローバルに、または関数全体に対してローカルに定義するvarキーワードとは異なります。
プログラムと関数のトップレベルでは、varとは異なり、letはグローバルオブジェクトにプロパティを作成しません。例えば:
var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined
varで宣言された変数のスコープは、現在の実行コンテキストです。これは、囲んでいる関数であるか、宣言された変数の場合は関数の外側、グローバル。 JavaScript変数を再宣言しても、その値は失われません。例えば:
var x = 1;
if (x === 1) {
var x = 2;
console.log(x);
// output: 2
}
console.log(x);
// output: 2
注:[〜#〜] c [〜#〜]とは異なり、C++、およびJava、varを使用して変数を宣言すると、JavaScriptにはブロックレベルのスコープがありません。 。
前に述べたようにletを使用すると、スコープがブロック、ステートメント、または式に限定されている変数を宣言できます。使用されます。例えば:
let x = 1;
if (x === 1) {
let x = 2;
console.log(x);
// output: 2
}
console.log(x);
// output: 1
ここでは、 変数スコープ について読むことをお勧めします
letキーワードで宣言された変数は、グローバルオブジェクトにアクセス可能なプロパティを作成しません(ブラウザの場合はwindow)。実際、Firefoxはその動作を修正しました:let v = 42; 'v' in window // false