[解決済み】Javascriptの変数宣言の構文の違い(グローバル変数を含む)?
質問
変数を宣言するのとしないのとでは、何か違いがあるのでしょうか?
var a=0; //1
...このように
a=0; //2
...または
window.a=0; //3
グローバルスコープで?
解決方法は?
はい、いくつかの違いがありますが、実用上は通常大きな違いではありません。
4つ目の方法があり、ES2015(ES6)時点ではさらに2つあります。4つ目の方法は最後に追加しましたが、ES2015の方法は#1の後に挿入しました(理由はおわかりになると思います)ので。
var a = 0; // 1
let a = 0; // 1.1 (new with ES2015)
const a = 0; // 1.2 (new with ES2015)
a = 0; // 2
window.a = 0; // 3
this.a = 0; // 4
これらの記述の説明
#1
var a = 0;
のプロパティでもあるグローバル変数が作成されます。
グローバルオブジェクト
としてアクセスします。
window
ブラウザ上で(または
this
をグローバルスコープに設定することができます(非制限的なコード)。他のいくつかのプロパティとは異なり、このプロパティは
delete
.
仕様の用語では、これは 識別子バインディング を指定します。 オブジェクト 環境記録 に対して グローバル環境 . なぜなら、グローバルオブジェクトは、グローバル環境のオブジェクトEnvironment Recordの識別子バインディングが保持される場所だからです。このため、このプロパティは削除できないようになっています。これは単なるプロパティではなく、識別子バインディングなのです。
バインディング(変数)は、コードの最初の行が実行される前に定義されます("When
var
happens"以下同様)。
なお、IE8以前では、このプロパティは
window
は
列挙可能
(で表示されない)。
for..in
ステートメント)。IE9、Chrome、Firefox、Operaでは、列挙可能です。
#1.1
let a = 0;
これは、グローバル変数を作成します。 ではない グローバルオブジェクトのプロパティです。これはES2015の時点では新しいことです。
仕様の用語で言うと、これは
宣言的
グローバル環境用の環境レコードではなく
オブジェクト
環境レコードです。グローバル環境は環境レコードが分割されているのが特徴で、1つはグローバルオブジェクトにある古いもの全てに対応するものです(
オブジェクト
環境レコード)と、すべての新しいもの(
let
,
const
で作成された関数、および
class
) のうち、グローバルオブジェクトに乗らないものです。
バインディングは
作成
その囲むブロック内のステップバイステップのコードが実行される前に(この場合、グローバルコードが実行される前に)、しかし、それは
アクセス可能
に到達するまでは、どのような形であれ、その実行は継続されます。
let
ステートメントを使用します。実行が
let
ステートメントを使用すると、その変数にアクセスできるようになります。(参照: "When
let
と
const
以下、happen" とします)。
#1.2
const a = 0;
グローバルオブジェクトのプロパティではないグローバル定数を作成します。
const
は、まさに
let
ただし、イニシャライザを用意しなければならない (
= value
の部分)があり、一度作成した定数の値を変更することはできません。裏を返せば、これはまさに
let
というフラグを識別子のバインディングにつけて、その値を変更できないようにしています。使用方法
const
は、3つのことをやってくれます。
- 定数に代入しようとすると、パースタイムエラーになるようにする。
- 他のプログラマーのために、その不変の性質を文書化する。
- JavaScriptエンジンが変化しないことを前提に、最適化させる。
#2
a = 0;
これは、グローバルオブジェクトにプロパティを作成します。 暗黙のうちに . 通常のプロパティなので、削除しても問題ありません。私がお勧めするのは ではなく これは、後であなたのコードを読む人にとって不明瞭になる可能性があります。ES5のストリクトモードを使用している場合、このようなこと(存在しない変数への代入)はエラーになります。これは、ストリクトモードを使用するいくつかの理由のうちの一つです。
そして興味深いことに、やはりIE8以前では、作成されたプロパティは
列挙可能
(で表示されない)。
for..in
ステートメント)。特に以下の3番を考えると、それは奇妙なことです。
#3
window.a = 0;
これは、グローバルオブジェクトのプロパティを明示的に作成するものです。
window
グローバルオブジェクトを参照するグローバル変数 (ブラウザの場合。ブラウザ以外の環境では、同等のグローバル変数、たとえば
global
NodeJSの場合)。通常のプロパティなので、削除しても大丈夫です。
このプロパティ は が、IE8以前、そして私が試した他のすべてのブラウザで、列挙可能です。
#4
this.a = 0;
3と全く同じですが、グローバルオブジェクトを参照するために
this
ではなく、グローバルな
window
. しかし、これはストリクトモードでは機能しません。ストリクトモードでは、グローバルなコードです。
this
はグローバルオブジェクトへの参照を持っていない (それは値として
undefined
となります。)
プロパティの削除
削除とはどういう意味ですか?
a
? まさにその通りです。プロパティを(完全に)削除するには
delete
というキーワードがあります。
window.a = 0;
display("'a' in window? " + ('a' in window)); // displays "true"
delete window.a;
display("'a' in window? " + ('a' in window)); // displays "false"
delete
は、オブジェクトからプロパティを完全に削除します。に追加されたプロパティでは、そのようなことはできません。
window
を経由して間接的に
var
は、その
delete
は黙って無視されるか、例外が投げられます (JavaScriptの実装と、ストリクトモードかどうかに依存します)。
警告
: IE8を再び(おそらくそれ以前も、IE9-IE11を壊れた"compatibility"モードでも)。のプロパティを削除できない。
window
オブジェクトを使用することが許可されている場合でもです。さらに悪いことに、それは
例外
を試すと (
この実験をやってみる
IE8や他のブラウザでは)。から削除すると
window
オブジェクトを使用する場合は、守りを固める必要があります。
try {
delete window.prop;
}
catch (e) {
window.prop = undefined;
}
これはプロパティの削除を試み、例外が発生した場合は、次善の策を講じてプロパティを
undefined
.
これは
のみ
が適用されます。
window
オブジェクトは、(私の知る限り)IE8以前(または壊れた"互換性"モードのIE9-IE11)のみで使用可能です。他のブラウザでは
window
プロパティは、上記のルールに従います。
いつ
var
起こる
で定義された変数は
var
ステートメントが作成される前に
任意の
実行コンテキスト内のステップバイステップのコードが実行されるため、このプロパティはよく存在する
前
は
var
ステートメントを使用します。
これは分かりにくいので、見てみましょう。
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "undefined"
display("bar in window? " + ('bar' in window)); // displays "false"
display("window.bar = " + window.bar); // displays "undefined"
var foo = "f";
bar = "b";
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "f"
display("bar in window? " + ('bar' in window)); // displays "true"
display("window.bar = " + window.bar); // displays "b"
ライブの例です。
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "undefined"
display("bar in window? " + ('bar' in window)); // displays "false"
display("window.bar = " + window.bar); // displays "undefined"
var foo = "f";
bar = "b";
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "f"
display("bar in window? " + ('bar' in window)); // displays "true"
display("window.bar = " + window.bar); // displays "b"
function display(msg) {
var p = document.createElement('p');
p.innerHTML = msg;
document.body.appendChild(p);
}
ご覧のように、シンボル
foo
は最初の行の前に定義されていますが、シンボル
bar
はない。ここで
var foo = "f";
シンボルの定義(これはコードの最初の行が実行される前に行われます)と、そのシンボルへの代入(これはステップバイステップの流れの中でその行がある場所で行われます)です。これは、「"」と呼ばれるものです。
var
を使用するためです。
var foo
部分はスコープの最上部に移動 ("hoisted") しますが
foo = "f"
の部分は元の場所に残されます。(参照
貧乏人の勘違い
var
私の貧弱な小さなブログで)
いつ
let
と
const
起こる
let
と
const
とは異なります。
var
を、いくつかの点から説明します。質問に関連する方法は、それらが定義するバインディングはステップバイステップのコードが実行される前に作成されますが、それは
アクセス可能
になるまで
let
または
const
文に到達したとき。
だから、これが実行されている間は
display(a); // undefined
var a = 0;
display(a); // 0
これはエラーを投げます。
display(a); // ReferenceError: a is not defined
let a = 0;
display(a);
という他の2つの方法があります。
let
と
const
とは異なります。
var
という、質問とはあまり関係のないものがあります。
-
var
は常に実行コンテキスト全体 (グローバルコード全体、またはそれが現れる関数内の関数コード全体) に適用されますがlet
とconst
の中だけに適用されます。 ブロック が表示されます。つまりvar
は関数(またはグローバル)スコープを持ちますがlet
とconst
はブロックスコープを持ちます。 -
繰り返し
var a
を同じコンテキストで使用することは無害ですが、もしあなたがlet a
(またはconst a
) を持つことで、別のlet a
またはconst a
またはvar a
はシンタックスエラーです。
以下はそのデモ例です。
let
と
const
は、そのブロック内のコードが実行される前に、そのブロック内ですぐに有効になりますが
let
または
const
ステートメントを使用します。
var a = 0;
console.log(a);
if (true)
{
console.log(a); // ReferenceError: a is not defined
let a = 1;
console.log(a);
}
なお、2番目の
console.log
にアクセスするのではなく、失敗します。
a
をブロックの外から実行します。
オフトピです。グローバルオブジェクトを散らかさないようにする (
window
)
は
window
オブジェクトはプロパティでとてもとてもごちゃごちゃしています。可能な限り、このようなごちゃごちゃを増やさないことを強くお勧めします。その代わりに、シンボルを小さなパッケージにまとめ、次のようにエクスポートしてください。
最も
に1つのシンボルを
window
オブジェクトを作成します。(私は頻繁に
任意
シンボルを
window
オブジェクトを作成します)。シンボルを格納するために、すべてのコードを格納する関数を使用することができます。その関数は、あなたが望むなら、匿名にすることができます。
(function() {
var a = 0; // `a` is NOT a property of `window` now
function foo() {
alert(a); // Alerts "0", because `foo` can access `a`
}
})();
この例では、関数を定義してすぐに実行させています(
()
を最後に追加します)。
このように使われる関数は、よく スコープ関数 . スコープ関数の中で定義された関数は、スコープ関数で定義された変数にアクセスできます。 クロージャ をそのデータの上に置く(参照。 クロージャは複雑ではない を私の貧弱な小さなブログで紹介します)。
関連
-
[解決済み】Redux TypeError: 未定義のプロパティ 'apply' を読み取れない
-
[解決済み】SyntaxError: 期待された式が、'<'を得た。
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] let "と "var "の使い分けは?
-
[解決済み] JavaScript で配列に値が含まれているかどうかを確認するにはどうすればよいですか?
-
[解決済み] callとapplyの違いは何ですか?
-
[解決済み] event.preventDefault() vs. return false
-
[解決済み] JavaScriptでNULL、未定義、空白の変数をチェックする標準的な関数はありますか?
-
[解決済み] JavaScriptの配列宣言で「Array()」と「[]」はどう違うのですか?
-
[解決済み】JavaScript版sleep()とは?)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】フォームコントロールの値アクセサがない
-
[解決済み】TypeError: 'undefined'はオブジェクトではありません。
-
[解決済み】NodeJS "ESモジュールをロードするためにインポートを使用する必要があります。"
-
[解決済み】React.jsの配列の子要素のユニークキーを理解する
-
[解決済み】npm install --legacy-peer-deps は具体的に何をするのですか?どんなときに推奨されるのか/どんな使用例が考えられるのか?
-
[解決済み】Redux TypeError: 未定義のプロパティ 'apply' を読み取れない
-
[解決済み】 Uncaught Reference Error: stLight is not defined (in Chrome only)
-
[解決済み】react router v^4.0.0 Uncaught TypeError: 未定義のプロパティ'location'を読み取れない
-
[解決済み] JavaScriptの関数でグローバル変数を定義する
-
[解決済み] JavaScript ファイルにパラメータを渡す