web-dev-qa-db-ja.com

変数の宣言と初期化?

変数の宣言と変数の初期化の違いを知りたいです。例えば.

var example; // this is declaring

var example = "hi" // initializing? Or just "adding a value"?

私はそこにいるとは思いませんが、それぞれの定義は正確には何ですか?それとも基本的に同じ意味ですか?

10
user3247128

編集:@ThisClarkはコメントで何かを言った、そして私は彼が間違っていることを証明するために行った、そしてスペックをもう少し読んだときに私は何かを学んだ:

仕様 以外の情報は次のとおりです。

varステートメントは、実行中の実行コンテキストのVariableEnvironmentにスコープされる変数を宣言します。 Var変数は、それらを含むLexical Environmentがインスタンス化されるときに作成され、作成時にundefinedに初期化されます。 [...] Initializerを使用してVariableDeclarationで定義された変数には、変数の作成時ではなく、VariableDeclarationの実行時にInitializerのAssignmentExpressionの値が割り当てられます。

私がこれを読んだことに基づいて、次の点は、あなたが質問で尋ねた振る舞い(および用語の「正しい」使用法)を説明しています。

  • A 変数宣言(例:var foo)は、「字句環境」がインスタンス化されるとすぐに、その変数をcreatedにします。たとえば、その変数が関数本体内で定義されている場合、その関数は「字句環境」であるため、変数の作成は関数自体のインスタンス化と一致します。

  • 明らかに、変数宣言初期化子(つまり、変数の初期値に解決される右辺の式)で作成される場合とされない場合があります。これは「初期値」という用語のかなり非仕様的な使用法ですが...もう少し掘り下げてみましょう。

  • 技術的に、ここでの仕様書によると、すべての変数は値undefinedで初期化されます。

    変数が作成され[...]、未定義に初期化されます

    initializerも提供された場合、これは主に学術的なものであるため、そこでは「技術的に」強調します。

  • すでに説明したことに基づいて、ステートメントvar foo;が存在する可能性がありますanywhere関数本体内で、同じ関数内の他の場所に移動しても、関数自体の実行時セマンティクスには影響しません(実際の割り当てやその他の参照があるかどうかに関係なくto fooが発生します)。それでも混乱する場合は、前のポイントを読み直してください。

  • 動作の最後の部分は最も直感的な部分であり、それはinitializerassignmentです。この割り当ては、そのコード行が実際にexecutedであるときに行われます(これも、変数が技術的に取得された時点と同じではありませんcreated)。

したがって、簡単に要約すると、次のようになります。

  • All変数宣言(varを使用)は常に字句環境の初期化時にundefinedで初期化されます。
  • この初期化は、技術的な意味では、おそらくassignmentとしてカウントされません(ha、@ ThisClark、あなたwere間違っています!!)。 :)
  • 割り当ては、期待どおりに(そしてその時点で)動作するため、簡単な部分です。

それがお役に立てば幸いです(そして私が仕様をひどく誤解しなかったことを!)。

14
jmar777

@ jmar777の答えは、間違いなく仕様の最良の説明と内訳です。ただし、実践的な学習者にとっては、少し説明的なコードが役立つことがわかりました。 ;)


基本的な考え方

  • 「宣言」は、指定されたスコープ全体で変数を使用できるようにします。
  • 'Assignment'は、コード内のその場所で変数に特定の値を与えます。そのスコープまたは親スコープで宣言されたことがない変数に値を割り当てようとすると、変数はグローバルスコープで暗黙的に宣言されます(window.varName = valueと入力するのと同じです)。
  • 「初期化」とは、いわば「舞台裏」や「ボンネットの下」で起こることです。実行時に、すべてのdeclared変数は初期化で始まりundefinedのassignment(コードの最初の行ですぐに別の値が割り当てられた場合でも)。

したがって、初期化は私たちにとって重要な用語ではありません。宣言して割り当て、Javascriptエンジンを初期化します。

だからあなたの質問の例に直接答えるには:

  • var example;は変数を宣言し、初期化中にundefinedの値が割り当てられます。
  • var example = "hi"は変数を宣言し、最初はundefinedの値も割り当てられますが、実行中に実際にそのコード行に到達すると、文字列「hi」に再割り当てされます。


例示的なコード

function testVariableDeclaration() {

    // This behaves 'as expected'....

    console.log(test2, 'no value assigned yet'); // --> undefined 'no value assigned yet'

    // ....but shouldn't our actual expectation instead be that it'll throw an error since
    // it doesn't exist yet? See the final console.log() below!


    // As we all know....

    test1 = 'global var'; // ....a variable assignment WITHOUT declaration in the current
                          // scope creates a global. (It's IMPLICITLY declared.)

    // But a little counter-intuitively....

    test2 = 'not global'; // Although this variable also appears to be assigned without
                          // declaration like 'test1', the declaration for 'test2' that
                          // appears *later* in the code gets hoisted so that it's already
                          // been declared in-scope prior to this assignment.

    console.log( test1, window.test1 === test1 ); // --> 'global var' TRUE
    console.log( test2, window.test2 === test2 ); // --> 'not global' FALSE

    var test2; // As shown by the above console.log() outputs, this variable is scoped.

    console.log( test3 ); // Throws a ReferenceError since 'test3' is not declared
                          // anywhere, as opposed to the first console.log() for 'test2'.
}


宣言/割り当てに対する「スコープ」の影響

宣言と代入の違いをさらに明確にするのは、declaring変数が常に現在のスコープ内に新しい変数を作成することです(myVar- scopeB)、同じ名前の変数が親スコープにすでに存在している場合でも(myVarscopeA)。次に、新しい値をmyVar割り当てすることができますscopeB現在のスコープ内の任意の時点で、再宣言する必要はありません。 (この割り当ては、myVarの値には影響しません。scopeA。)の終わりにscopeBに到達、myVarscopeBは割り当てに使用できなくなります。

反対に、特定のスコープ内の変数に、そのスコープ内で宣言せずに値を割り当てると、次のスコープに割り当てられます。 -「スコープチェーン」の最上位宣言(または、上位の宣言が見つからない場合、グローバルは暗黙的に宣言されます)。

したがって、変数はスコープごとに1回宣言する必要があります。各宣言は親スコープで行われた宣言をオーバーライドします(つまり、個別の変数を作成します)。ただし、スコープに固有であることが意図されている場合は、スコープ内で宣言する必要があります。代入は必要に応じて何度でも行うことができますが、最も「厳密に宣言された」変数にのみ影響します(より適切な用語がないため)。

4
Marcus Hughes

唯一の違いは、varステートメントが値なしで宣言された変数をundefinedに初期化する

どちらの例でも、変数を宣言しています。

varステートメントなしで変数に値を割り当てると、スコープチェーンを下って宣言された変数を探し、最終的にグローバルwindowオブジェクトにフォールバックします。

0
bryc

宣言とは、基本的に、プログラムに新しいエンティティを導入することを意味します。初期化とは、変数に最初の値を与えることです。したがって、基本的に上記の例は正しいです。

0
deeeeeeekun

ここに欠けている小さなことがあります。概念を理解するためのアナロジーはこのようなものです。変数ごとに、何らかの値を割り当てる必要があります。

すべての変数のデフォルト値(明示的に言及されていない場合は未定義)

1) let example; // this is declaring and initializing with undefined

2) example="hi"; // this is assigning the value to hi

3) let example = "hi" // this is declaring and initializing with "hi"

したがって、3番目のステートメントは実質的に1 +2と同じです。

さて、ステートメント3が可能であるのに、なぜステートメント1が必要なのかという疑問が生じるかもしれません。

その理由は、変数の範囲を拡大するためです。

例えば行番号8に変数が必要であるとしましょう。しかし、値は遅くまで利用できず、それもコードブロックで利用できます。

1) {
2)  let a;
3)  try{
4)   a=someFunctionWhichMayThroeException();
5)  }
6)    catch(e){
7)         a=100;
8)  }
9)  someFunctionOnA(a);// the variable is required here
10)
11)  }

上記の変数を宣言することにより、変数のスコープが拡大され、tryブロックの外部で使用できるようになりました。

PS:これは使い方のほんの一例です。

0
Mohit Kanwar

宣言とは、プログラムに新しい名前を導入することです。

var test;        // Is this a declaration ?

初期化とは、値の「割り当て」を指します。

var test = {first:"number_one"}  // Now that object is initialized with value