私はしばらくの間ES6で遊んできましたが、var
で宣言されたwhile変数が期待通りに巻き上げられていることに気づきました...
console.log(typeof name); // undefined
var name = "John";
... let
またはconst
で宣言された変数は、巻き上げに問題があるようです。
console.log(typeof name); // ReferenceError
let name = "John";
そして
console.log(typeof name); // ReferenceError
const name = "John";
これは、let
またはconst
で宣言された変数がホイストされていないという意味ですか?本当にここで何が起こっているの?この問題でlet
とconst
の間に違いはありますか?
@thefourtheyeは、宣言される前にこれらの変数アクセスできないと言っているのが正しいです。しかし、それはそれより少し複雑です。
let
name__またはconst
name__で宣言された変数はホイストされていませんか?本当にここで何が起こっているの?
すべての宣言(var
name__、let
name__、const
name__、function
name__、function*
、class
name__)JavaScriptでは「含まれている」これは、名前がスコープ内で宣言されている場合、そのスコープ内で識別子が常にその特定の変数を参照することを意味します。
x = "global";
// function scope:
(function() {
x; // not "global"
var/let/… x;
}());
// block scope (not for `var`s):
{
x; // not "global"
let/const/… x;
}
これは、関数スコープとブロックスコープの両方に当てはまります。1。
var
name __/function
name __/function*
宣言とlet
name __/const
name __/class
name__宣言の違いは初期化です。
前者は、バインディングがスコープの先頭に作成されたときに、undefined
name__または(generator)関数で初期化されます。ただし、字句的に宣言された変数は未初期化のままです。つまり、アクセスしようとするとReferenceError
name__例外がスローされます。 let
name __/const
name __/class
name__ステートメントが評価されるときにのみ初期化されます。それ以前の一時的デッドゾーンと呼ばれるものすべてです。
x = y = "global";
(function() {
x; // undefined
y; // Reference error: y is not defined
var x = "local";
let y = "local";
}());
let y;
ステートメントがlet y = undefined;
のようにundefined
name__で変数を初期化することに注意してください。
一時的なデッドゾーンは構文上の場所ではなく、時間です。変数(スコープ)の作成と初期化の間そのコードが実行されない限り宣言の上のコードで変数を参照することはエラーではありません、そして初期化の前に変数にアクセスしたとしても、初期化の前に変数にアクセスすれば例外を投げます。コードが宣言の下にあります(たとえば、呼び出しが早すぎる呼び出し関数宣言の中など)。
この問題で
let
name__とconst
name__の間に違いはありますか?
いいえ、吊り上げに関しては同じように機能します。唯一の違いは、const
name__antは宣言のイニシャライザ部分でのみ割り当てられ、割り当てられることができるということです(const one = 1;
、const one;
およびそれ以降のone = 2
のような再割り当ては無効です)。
1:var
name__宣言は、もちろん関数レベルでのみ機能しています、もちろん
ECMAScript 6(ECMAScript 2015)仕様の引用符、 let
およびconst
の宣言 section、
含まれているLexical Environmentがインスタンス化されたときに変数が作成されますが、変数のLexicalBindingが評価されるまでにアクセスすることはできません。
したがって、あなたの質問に答えるために、はい、let
およびconst
ホイストですが、実際の宣言が実行時に評価される前にそれらにアクセスすることはできません。
ES6
はblock level scoping
を思い付くLet
変数を紹介します。 ES5
まで我々はblock level scoping
を持っていませんでした、それでブロックの中で宣言される変数は関数レベルの有効範囲に対して常にhoisted
です。
基本的にScope
はあなたのプログラムのどこであなたの変数が見えるかを参照します、それはあなたが宣言した変数を使うことが許される場所を決定します。 ES5
にはglobal scope,function scope and try/catch scope
があり、ES6
にはLetを使ってブロックレベルのスコープを取得することもできます。
var
キーワードで変数を定義すると、それが定義された瞬間から関数全体がわかります。let
ステートメントで変数を定義すると、その変数は定義されているブロック内でしか認識されません。
function doSomething(arr){
//i is known here but undefined
//j is not known here
console.log(i);
console.log(j);
for(var i=0; i<arr.length; i++){
//i is known here
}
//i is known here
//j is not known here
console.log(i);
console.log(j);
for(let j=0; j<arr.length; j++){
//j is known here
}
//i is known here
//j is not known here
console.log(i);
console.log(j);
}
doSomething(["Thalaivar", "Vinoth", "Kabali", "Dinesh"]);
コードを実行すると、変数j
はloop
内でのみ認識され、前後には認識されないことがわかります。しかし、変数i
は、定義された瞬間からentire function
で認識されています。
Letをそのまま使用するもう1つの大きな利点があります。新しいレキシカル環境を作成し、古い参照を保持するのではなく、新しい値をバインドします。
for(var i=1; i<6; i++){
setTimeout(function(){
console.log(i);
},1000)
}
for(let i=1; i<6; i++){
setTimeout(function(){
console.log(i);
},1000)
}
最初のfor
ループは常に最後の値を表示し、let
を指定すると新しいスコープを作成し、新しい値をバインドして1, 2, 3, 4, 5
を出力します。
constants
に来ると、それは基本的にlet
のように動作します、唯一の違いはそれらの値が変更できないことです。定数では変更は許可されていますが、再割り当ては許可されていません。
const foo = {};
foo.bar = 42;
console.log(foo.bar); //works
const name = []
name.Push("Vinoth");
console.log(name); //works
const age = 100;
age = 20; //Throws Uncaught TypeError: Assignment to constant variable.
console.log(age);
定数がobject
を参照する場合、それは常にobject
を参照しますが、object
自体は変更可能です(変更可能な場合)。不変のobject
を使いたい場合は、Object.freeze([])
を使用できます。
ECMAScript 2015では、let
およびconst
は吊り上げられていますが、初期化されていません。変数はブロックの開始から宣言が処理されるまで「一時的なデッドゾーン」にあるため、変数宣言の前にブロック内の変数を参照するとReferenceError
になります。
console.log(x); // ReferenceError
let x = 3;