2016-02-24 8 views
6

私はletは、ブロックの上に掲揚されますが、初期化する前に、それへのアクセスは例えばTemporal Dead ZoneES6で巻き上げをする目的は何ですか?

にあることに起因ReferenceErrorを投げることを理解:

console.log(x); // Will throw Reference Error 
let x = 'some value'; 

しかし、このようなスニペットはせずに実行されますエラー:

foo(); // alerts foo; 
function foo(){ // foo will be hoisted 
    alert("foo"); 
} 

私の質問

letの目的はアクセス時にエラーを投げるときに上に上がりますか?また、varはTDZに苦しんでいますか、私はそれがundefinedを投げる時を知っていますが、TDZのためですか?

+0

["let"キーワードと "var"キーワードの重複の可能性があります(http://stackoverflow.com/questions/762011/let -keyword-vs-var-keyword) –

+1

@ MarcosPrezGudemyの疑問は、巻上げに関連しています。アクセスにエラーが発生しても、差をつけさせてください。しかし、あなたが共有したリンクは、letとvarの違いについてもっと詳しく教えてくれます。 – brk

+0

申し訳ありませんが、私は吊り上げが何であるか分かりませんでしたが、今はすべて明らかです。私は私の重複投票を削除します。 –

答えて

4

documentationは言う:

The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable's LexicalBinding is evaluated. A variable defined by a LexicalBinding with an Initializer is assigned the value of its Initializer's AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created. If a LexicalBinding in a let declaration does not have an Initializer the variable is assigned the value undefined when the LexicalBinding is evaluated.

またvar keyword

let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.

また、カイル・シンプソンことで、この記事をチェックすることができます。For and against let

0

あなたが最初の巻き上げを理解する必要があります。これはブロックの先頭にコード宣言の初期化を取っているあなたは値が他にも機能にアクセスすることが見ることができるよう、

function getValue(condition) { 
    if (condition) { 
     var value = "blue"; 
     // other code 
     return value; 
    } else { 
     // value exists here with a value of undefined 
     return null; 
    } 
     // value exists here with a value of undefined 
} 

次の例を検討してください。 getValue(condition)関数の直後に宣言されているため。

function getValue(condition) { 
    if (condition) { 
     let value = "blue"; 
     // other code 
     return value; 
    } else { 
     // value doesn't exist here 
     return null; 
    } 
    // value doesn't exist here 
} 

しかし、私たちは聞かせて使用するときには、違いを見ることができます。例もさらに明確化

1

http://www.2ality.com/2015/10/why-tdz.html素敵な方法でそれを説明し、また、上の関連する議論があるhttps://mail.mozilla.org/pipermail/es-discuss/2012-September/024996.htmlにリンクするため

https://leanpub.com/understandinges6/read#leanpub-auto-var-declarations-and-hoisting

を見るために私が読んでいる本から取られて、あなたをお勧めしていますトピック。 TDZは、参照エラーが発生することはありませんでした、とあなたは(TDZでIE)その宣言の前に変数にアクセスした場合、あなたはおそらく(この質問

Why is there a temporal dead zone for let ?

  1. のためのコンテンツを思い言い換え

    )プログラミングミスを逃している。参照エラーを引き起こすTDZは、プログラミングミスを犯すのを助けます。

  2. あなたの次の質問は、となります。letのTDZがあるのはなぜですか?変数が宣言されたときにlet変数のスコープを開始してみませんか?答えはconstです。TDZsはconstletはちょうどいいえ、varはTDZを受けない

    Also do var also suffer from TDZ, I know when it will throw undefined but is it because of TDZ?


let間と constそれが簡単に切り替えできるようにすることTDZで捕まってしまった(貧困層)のためのものです。何のエラーも投げられません。それ以外は単に undefinedまで設定されています。 TDZはES6のものです。

-1

let変数が掲揚されていません。let変数が「掲揚」と言っては、技術的に正しいですが、私の意見では用語のこの使用は誤解を招くです。セマンティクスを記述するための同等の方法は、あなたがそれがまだ存在しないため、その宣言の上にそれを参照しようとすると、ReferenceErrorを得るということです。ブロック内のどこにも存在しない変数を参照しようとすると、同じことが起こります。

詳細情報:

C++とJavaScriptの両方がスコープをブロックしますが、この特定の時点では異なるので、我々は、彼らが異なる動作をどのように理解することでこの点を理解することができています。この例で考える:Cで

#include <iostream>               

int main() { 
    int x = 3; 

    { 
     std::cout << x << std::endl; 
     int x = 4; 
    } 

    return 0; 
} 

++実際には巻上は存在しないが、coutラインの実行時に第二xは(画面にxを印刷する)が存在しないが、第一xはまだない、などプログラムは順調に3をプリントします。それはかなり混乱しています。私たちは、代わりに曖昧で、それ誤り作るためにxへの言及を検討すべきです。

これはanalagous JavaScriptコードで何が起こるかです:

'use strict';                

let x = 3; 

(() => { 
    console.log(x); 
    let x = 4; 
})(); 

はJavaScriptでは、この問題は二xを「巻き上げ」が、アクセスしたとき、それはReferenceErrorをスローすることによって固定されています。それがあるべきとして私の知る限りでは、これは「巻き上げは」による曖昧にxエラーにその参照を行うことと等価です。

+0

変数をブロックの上部に持ち上げましょう://developer.mozilla.org/en/US/docs/Web/JavaScript/Reference/Statements/let – brk

+0

確かに、この仕様ではホイストですが、imoそれは誤解を招くような記述です。仕様を実装するときに得られる動作は、ホイストがなく、変数が有効範​​囲外にある場合と同じです。 – voltrevo

+0

@ user2181397私は、より詳細に説明する編集を追加しました。 – voltrevo

0

What is purpose of let getting hoisted to top when it will throw an error on accessing?

それはとても私たちがなしはバグや誤解の伝統的なソースであるvar巻き上げ、のブロックと同等を持つ、かなり理解しやすい概念であるブロックスコープを持つことができます。

{ 
    let a = 1; 
    console.log(a); 
    let b = 2; 
    console.log(a, b); 
    let c = 3; 
    console.log(a, b, c); 
} 

デザイナーがここに三つの主要な選択肢を持っていた:

は、このブロックの内部を考えてみましょう

  1. はブロックスコープを持っていますが、すべての宣言がトップに掲揚としてアクセス可能に(のようなvarですin関数);または
  2. はブロックスコープを持ち、代わりに新しい範囲がなどすべてのletconstclass、で始める必要はありません。;または
  3. は、宣言が掲揚されている場合、(または私は「半巻き上げ」と呼ぶもの)巻き上げて、ブロックスコープを持っていますが、それらは、コード

オプションに到達しているまで、彼らは宣言識別子はアクセスできません  1は、varホイストと同じ種類のバグに私たちを開放しています。オプション  2は、の方法です。人々が理解するのがより複雑であり、JavaScriptエンジンがより多くの作業を行います(必要な場合は以下の詳細を参照してください)。オプション  3つのスイートスポットがヒットします:ブロックスコープは理解しやすく、実装が容易で、TDZはvarホイストのようなバグを防ぎます。

Also do var also suffer from TDZ,I know when it will throw undefined but is it because of TDZ?

いいえ、var宣言にはTDZがありません。 undefinedではありませんは、変数が宣言されているがまだ何かに設定されていない場合の値です。 var宣言は関数またはグローバル環境の先頭に持ち込まれ、var行に達する前であっても、そのスコープで完全にアクセス可能です。


これは、識別子の解像度がJavaScriptで処理される方法を理解するのに役立つことがあります。

仕様はlexical environment, which contains an environment recordと呼ばれるものの面でそれを定義して、該当する場合は、変数、定数、関数パラメータ(に関する情報が含まれています)、class宣言など、現在のの文脈ではです。 (コンテキストは、exampleという関数がある場合、exampleの本文は新しいスコープを定義します; exampleを呼び出すたびに、そのスコープに新しい変数などがあります  コンテキストだ—。)

識別子(変数、等)に関する情報は、結合と呼ばれています。これには、識別子の名前、現在の値、その他の情報(変更可能か不変か、アクセス可能かどうかなど)が含まれます。

コード実行が新しいコンテキストに入ると(たとえば、関数が呼び出されたとき、またはletなどを含むブロックを入力したとき)、JavaScriptエンジンは環境とともに新しい字句環境オブジェクト(LEO)を作成します*レコード(envrec)を作成し、それを含む「外側の」LEOへのリンクをLEOに与え、チェーンを形成する。エンジンが識別子をルックアップする必要があるとき、最上位のLEOのenvrecでバインディングを探し、見つかった場合はそれを使用します。見つからなければ、チェーンの次のLEOを見て、チェーンの最後に到達するまで続きます。

ブロックスコープを有効にするためのES2015の変更点と、letconstなどの変更点については、おそらく推測しています(チェーンの最後のリンクは地球環境向けです)。基本的にあった。そのブロックはブロックスコープの宣言が含まれている場合

  • 新しいLEOはTDZが
を強制することができるので、LEOで
  • バインディングは、「アクセス不可」とマークすることができる、ブロックのために作成することができます心の中ですべてのことで

    は、のは、このコードを見てみましょう:exampleが呼び出されると

    function example() { 
        console.log("alpha"); 
        var a = 1; 
        let b = 2; 
        if (Math.random() < 0.5) { 
         console.log("beta"); 
         let c = 3; 
         var d = 4; 
         console.log("gamma"); 
         let e = 5; 
         console.log(a, b, c, d, e); 
        } 
    } 
    

    、どのエンジンは、(少なくとも、スペックの面で)それを処理しますか?このように:

      1. それは価値undefinedを持つすべての、それはそのLEOのenvrecにab、およびdのためのバインディングを追加しますexample
      2. への呼び出しのコンテキストのLEOを作成しますそれがvarバインディングであるため、関数のどこにでも置かれているため、aが追加されます。その "accessible"フラグはtrueに設定されています(varのため)。
      3. bが追加されました。これは、関数の最上位レベルでletバインディングであるためです。 let b行にまだ到達していないため、その "accessible"フラグはfalseに設定されています。
      4. dvarバインディングなので、aのようになります。
  • console.log("alpha")を実行します。
  • a = 1を実行し、aのバインド値をundefinedから1に変更します。
  • let bを実行し、bバインディングの "accessible"フラグをtrueに変更します。
  • bのバインド値をundefinedから2に変更して、b = 2を実行します。
  • Math.random() < 0.5と評価されます。のは、それが本当だとしましょう:
  • ブロックはブロックスコープの識別子が含まれているため、エンジンはステップで作成したものに、その「外側」LEOを設定、ブロックのための新しいLEOを作成  1.
  • それはcのためのバインディングを追加しますLEOのenvrecにはeが、アクセス可能フラグはfalseに設定され、値はundefinedに設定されています。
  • ​​を実行します。
  • それはそれはc = 3を実行し、真
  • への 『アクセス』のフラグを結合c年代を設定し、let c実行されます。
  • d = 4を実行します。
  • console.log("gamma")を実行します。
  • eのバインディングの "accessible"フラグをtrueに設定して、let eを実行します。
  • e = 5を実行します。
  • console.log(a, b, c, d, e)を実行します。うまくいけば、
  • その答え:

    • なぜ我々は(それが簡単にスコープを理解することができるようにするには、あまりにも多くのレオとenvrecsを避けるために、ブロックレベルでのバグを回避するためにlet半巻き上げを持っていますvar
    var変数のバインディングの「アクセス」フラグは常に真である)TDZを持っていないのはなぜvar巻き上げ)は関数レベルで
  • を持っていたもののような

    *少なくとも、それは仕様の点で何をしているのですか。実際には、仕様どおりに動作するならば、好きなことを行うことができます。実際には、ほとんどのエンジンはスタックなどを利用して、より効率的な処理を行います。

  • 関連する問題