web-dev-qa-db-ja.com

ステートメントでグローバルオブジェクトにプロパティを作成できますか?

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
45

letステートメントはグローバルオブジェクトにプロパティを作成しますか?

spec によると、いいえ:

グローバル環境レコードは論理的には単一のレコードですが、 オブジェクト環境レコード宣言型環境レコード をカプセル化する複合として指定されます。 オブジェクト環境レコード は、そのベースオブジェクトとして、関連付けられた レルム のグローバルオブジェクトを持っています。このグローバルオブジェクトは、グローバル環境レコードのGetThisBinding具象メソッドによって返される値です。グローバル環境レコードのオブジェクト環境レコードコンポーネントには、すべての組み込みグローバルのバインディング( 18節 )と、FunctionDeclarationGeneratorDeclarationによって導入されたすべてのバインディングが含まれます。、またはVariableStatementグローバルコードに含まれています。 グローバルコード内の他のすべてのECMAScript宣言のバインディングは、グローバル環境レコードの 宣言型環境レコード コンポーネントに含まれています。

もう少し説明:

  • declarative環境レコードは、バインディングを内部データ構造に格納します。そのデータ構造を取得することは決して不可能です(関数スコープについて考えてください)。

  • object環境レコードは、実際のJSオブジェクトをデータ構造として使用します。オブジェクトのすべてのプロパティがバインディングになり、その逆も同様です。グローバル環境には、「バインディングオブジェクト」がグローバルオブジェクトであるオブジェクト環境オブジェクトがあります。別の例はwithです。

さて、引用された部分が述べているように、FunctionDeclaration s、GeneratorDeclaration s、およびVariableStatement sだけが、グローバル環境のobject環境レコード。つまりこのバインディングのみがグローバルオブジェクトのプロパティになります。

他のすべての宣言(例:constおよびlet)は、グローバル環境のdeclarative環境レコードに格納されます。グローバルオブジェクトに基づいています。

43
Felix Kling

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>
5
Flimm

仕様による

「let宣言とconst宣言は、実行中の実行コンテキストのLexicalEnvironmentにスコープされる変数を定義します。」

これは、実行スコープの内側では変数にアクセスできるはずですが、外側ではアクセスできないことを意味します。これにより、実行範囲が、関数のみまたはグローバルの従来のJSクロージャ構造を超えて拡張されます。

let変数をグローバルに定義すると、Firefoxで見られるように、グローバル変数がバインドされますが、V8/iojsはバインドされません。

console.log(typeof x)がiojsでnumberをreturlすることは言及する価値があります。実際には、モジュールや関数の外部で変数を定義するべきではありません...特にconstletでは

4
Tracker1

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++、およびJavavarを使用して変数を宣言すると、JavaScriptにはブロックレベルのスコープがありません。 。

前に述べたようにletを使用すると、スコープがブロック、ステートメント、または式に限定されている変数を宣言できます。使用されます。例えば:

let x = 1;

if (x === 1) {
  let x = 2;

  console.log(x);
  // output: 2
}

console.log(x);
// output: 1

ここでは、 変数スコープ について読むことをお勧めします

0
S. Mayol

letキーワードで宣言された変数は、グローバルオブジェクトにアクセス可能なプロパティを作成しません(ブラウザの場合はwindow)。実際、Firefoxはその動作を修正しました:let v = 42; 'v' in window // false

0
daGo