JavaScript関数のスコープとホイスト


89

Ben CherryよるJavaScript Scoping and Hoistingに関するすばらしい記事を読んだところ、彼は次の例を示しています。

var a = 1;

function b() {
    a = 10;
    return;

    function a() {}
}
b();
alert(a);

上記のコードを使用すると、ブラウザは「1」を警告します。

それが「1」を返す理由はまだわかりません。彼が言うことのいくつかは次のように思い浮かびます:すべての関数宣言は上に持ち上げられます。関数を使用して変数のスコープを設定できます。まだクリックしません。

回答:


120

関数の巻き上げとは、関数がスコープの最上部に移動されることを意味します。あれは、

function b() {  
   a = 10;  
   return;  
   function a() {} 
} 

検閲官によってこれに書き換えられます

function b() {
  function a() {}
  a = 10;
  return;
}

変だよね?

また、この場合、

function a() {}

と同じように動作した

var a = function () {};

つまり、本質的に、これはコードが実行していることです。

var a = 1;                 //defines "a" in global scope
function b() {  
   var a = function () {}; //defines "a" in local scope 
   a = 10;                 //overwrites local variable "a"
   return;      
}       
b();       
alert(a);                 //alerts global variable "a"

2
したがって、すべての関数宣言は最終的に変数に割り当てられますか?
dev.e.loper 2011

15
@ dev.e.loperはい、Javascriptでは、関数は文字列や数値と同じようにファーストクラスオブジェクトです。つまり、これらは変数として定義され、他の関数に渡したり、配列に格納したりすることができます。
Peter Olson

4
関数本体が「書き換えられる」ことは決してありません。さまざまなECMAScript標準では、コードと変数の宣言がコードの実行を開始する前に処理されることが明記されています。つまり、何も移動されません。それは実行の順序に関するものです(したがって、「巻き上げ」という用語の私の嫌いさは、移動または再配置を推測します)。書き直したコードでは、宣言var aは関数宣言の前に、割り当てa = 1は後でなければなりません。ただし、これはパーサー、トークナイザー、インタープリター、コンパイラーなどによって実際に発生するように指定されていないことに注意してください。これは同等のものです。
RobG、2015

3
@RobG確かに、説明を小さな「子供たちへの嘘」と呼ぶことができると思いますが、結局のところ、コードが文字どおりに並べ替えられても、実行順序だけが並べ替えられても、動作は同じです。実際に舞台裏で何が起こるかは、学術的な関心事であり、実装に依存することさえあるかもしれません。
Peter Olson、2015

7
「また、このインスタンスでfunction a() {}はと同じように動作しましたvar a = function () {};  —これは2つの点で正しくありません。1つ目は、どちらかと言えばvar a = function a() {};そうでした(関数は実際には匿名ではない)、2つ目は、これら2つの形式は交換できません。var a = function a() {};そのvar a;部分だけが巻き上げられたでしょう。そのa = function a() {};部分はまだreturnステートメントの後ろにあったでしょう。元のフォームは関数宣言であり、関数式ではないため、実際には全体として巻き上げられます。
user4642212

6

覚えておく必要があるのは、関数全体を解析し、実行前にすべての変数宣言を解決することです。そう....

function a() {} 

本当になる

var a = function () {}

var a ローカルスコープにそれを強制し、変数スコープは関数全体を通るので、関数を作成してローカルスコープに宣言したため、グローバル変数aはまだ1です。


5

関数aはfunction 内に巻き上げられますb

var a = 1; 
function b() { 
   function a() {} 
   a = 10; 
   return;
} 
b(); 
alert(a);

これはほとんど使用のようvarです:

var a = 1; 
function b() { 
   var a = function () {};
   a = 10; 
   return;
} 
b(); 
alert(a);

関数はローカルで宣言され、設定aはローカルスコープでのみ発生し、グローバル変数では発生しません。


1
この行 "var a = function(){};"は、すべてのことを明確にします。基本的に、JavaScriptは動的言語であり、 "function"もJavaScriptのオブジェクトです。
2016年

3
  1. 関数宣言function a(){}が最初に巻き上げられ、のように動作するvar a = function () {};ため、ローカルスコープaに作成されます。
  2. 同じ名前の2つの変数がある場合(1つはグローバル、もう1つはローカル)、ローカル変数は常にグローバル変数より優先されます。
  3. を設定するa=10a、グローバル変数ではなくローカル変数が設定されます。

したがって、グローバル変数の値は同じままで、警告が表示されます1


1

function a() { }関数のaローカル変数を作成する関数ステートメントbです。
変数は、varor関数ステートメントが実行されるかどうかに関係なく、関数の解析時に作成されます。

a = 10 このローカル変数を設定します。


追加しない限り、関数が実行されるときに実際にグローバルスコープにa = 10変数を設定します(そのディレクティブをサポートするような環境では)。b"use strict"
Sean Vieira

@Sean:いいえ、機能ステートメントはローカル識別子を作成するためです。
SLaks、2009

...そして....あなたは正しい。関数の巻き上げの特定の結果に気づかなかった。ありがとう!
Sean Vieira

1

この小さなコードスニペットの競合の骨は何ですか?

ケース1:

以下のようにfunction a(){}本体に定義を含めfunction bます。logs value of a = 1

var a = 1;
function b() {
  a = 10;
  return;

  function a() {}
}
b();
console.log(a); // logs a = 1

事例2

以下function a(){}の本体内の定義を除外function bします。logs value of a = 10

var a = 1;
function b() {
  a = 10;  // overwrites the value of global 'var a'
  return;
}
b();
console.log(a); // logs a = 10

観察は、ステートメントconsole.log(a)が次の値をログに記録することを理解するのに役立ちます。

ケース1: a = 1

ケース2: a = 10

位置

  1. var a 語彙的にグローバルスコープで定義および宣言されています。
  2. a=10 このステートメントは、値を10に再割り当てしています。字句的には関数bの内部にあります。

両方のケースの説明

のためfunction definition with name propertyはと同じvariable aです。variable a内部のfunction body bローカル変数になります。前の行は、aのグローバル値はそのままで、aのローカル値が10に更新されることを意味します。

つまり、以下のコードは

var a = 1;
function b() {
  a = 10;
  return;

  function a() {}
}
b();
console.log(a); // logs a = 1

JSインタープリターによって次のように解釈されます。

var a = 1;
function b() {
  function a() {}
  a = 10;
  return;


}
b();
console.log(a); // logs a = 1

しかし、我々は削除するとfunction a(){} definitionvalue of 'a'機能Bの外側に宣言と定義し、その値が上書きされ、値が上書きために取得ケース2には10に変更a=10グローバル宣言を意味し、それがローカルに宣言されるならば、我々は持っている必要があります書かれたvar a = 10;

var a = 1;
function b() {
  var a = 10; // here var a is declared and defined locally because it uses a var keyword. 
  return;
}
b();
console.log(a); // logs a = 1

name propertyin function a(){} definitionを別の名前に変更することで、疑問をさらに明確にすることができます'a'

var a = 1;
function b() {
  a = 10; // here var a is declared and defined locally because it uses a var keyword. 
  return;

  function foo() {}
}
b();
console.log(a); // logs a = 1

1

巻き上げとは、理解を容易にするために作られた概念です。実際に起こることは、宣言がスコープに関して最初に行われ、割り当てがその後に行われることです(同時にではありません)。

宣言が発生するとvar afunction bそのbスコープ内でfunction aが宣言されます。

この関数aは、グローバルスコープからの変数aをシャドウします。

宣言が完了すると、値の割り当てが開始され、グローバルaが値を取得1し、内部function bがを取得し10ます。実行alert(a)すると、実際のグローバルスコープ変数が呼び出されます。コードへのこの小さな変更により、コードがより明確になります

        var a = 1;

    function b() {
        a = 10;
        return a;

        function a() { }
    }

    alert(b());
    alert(a);

1
codeschool.comのコースでさえ、多くの専門家が巻き上げに言及していることは奇妙です。参照:1)developer.mozilla.org/en-US/docs/Glossary/Hoisting 2)john resig、bear bebeault、josip marasによるJavaScript Ninja 2 / eの秘密の第5章
adnan2nd

1

驚いたことに、ここでの回答はいずれも、スコープチェーン内の実行コンテキストの関連性について言及していません。

JavaScriptエンジンは、現在実行中のコードを実行コンテキストにラップします。基本実行コンテキストは、グローバル実行コンテキストです。新しい関数が呼び出されるたびに、新しい実行コンテキストが作成され、実行スタックに置かれます。他のプログラミング言語の呼び出しスタック上にあるスタックフレームを考えてみてください。最初のうちの最後の。これで、各実行コンテキストには、JavaScriptで独自の変数環境と外部環境があります。

以下の例をデモとして使用します。

1)最初に、グローバル実行コンテキストの作成フェーズに入ります。字句環境の外部環境と可変環境の両方が作成されます。グローバルオブジェクトが設定され、特別な変数 'this'がそれを指すようにメモリに配置されます。関数aとそのコード、および値が未定義の変数myVarは、グローバル変数環境のメモリに配置されます。関数aのコードは実行されないことに注意することが重要です。関数aでメモリに配置されるだけです。

2)次に、実行コンテキストの実行フェーズです。myVarは未定義の値ではなくなりました。これは、グローバル変数環境に格納されている値1で初期化されます。関数aが呼び出され、新しい実行コンテキストが作成されます。

3)関数aの実行コンテキストでは、自身の実行コンテキストの作成および実行フェーズを通過します。独自の外部環境と可変環境があるため、独自の字句環境があります。関数bと変数myVarは、その変数環境に格納されます。この変数環境は、グローバル変数環境とは異なります。関数aはレキシカルに(物理的にはコードでは)グローバル実行コンテキストと同じレベルにあるため、その外部環境はグローバル実行コンテキストです。したがって、関数aが変数環境にない変数を参照する場合、スコープチェーンを検索し、グローバル実行コンテキストの変数環境で変数を見つけようとします。

4)関数bが関数aで呼び出されます。新しい実行コンテキストが作成されます。語彙的に関数aにあるため、その外部環境はaです。したがって、myVarを参照する場合、myVarは関数bの変数環境にないため、関数aの変数環境を調べます。そこにあり、console.logが2を出力します。ただし、変数が関数aの変数環境になかった場合、関数aの外部環境はグローバル実行コンテキストであるため、スコープチェーンはそこで検索を続けます。

5)関数bと関数aの実行が完了すると、実行スタックからポップされます。シングルスレッドのJavaScriptエンジンは、グローバルな実行コンテキストで実行を継続します。b関数を呼び出します。ただし、グローバル変数環境にはb関数はなく、グローバル実行コンテキストで検索する他の外部環境はありません。したがって、JavaScriptエンジンによって例外が発生します。

function a(){
  function b(){
    console.log(myVar);
  }

  var myVar = 2;
  b();
}

var myVar = 1;
a();
b();
> 2
> Uncaught ReferenceError: b is not defined

以下の例は、スコープチェーンの動作を示しています。関数bの実行コンテキストの変数環境には、myVarはありません。したがって、関数aである外部環境を検索します。関数aの変数環境にもmyVarがありません。したがって、エンジンは関数aの外部環境を検索します。これは、グローバル実行コンテキストの外部環境であり、myVarがそこで定義されています。したがって、console.logは1を出力します。

function a(){
  function b(){
    console.log(myVar);
  }

  b();
}

var myVar = 1;
a();
> 1

実行コンテキストと、それに関連付けられている字句環境(外部環境や変数環境を含む)については、JavaScriptで変数のスコープを有効にします。同じ関数を複数回呼び出しても、呼び出しごとに独自の実行コンテキストが作成されます。したがって、各実行コンテキストには、その変数環境に変数の独自のコピーがあります。変数の共有はありません。


0

これは、変数名が関数名が「a」を意味するのと同じであるために発生しています。したがって、Javascriptホイストにより、名前の競合を解決しようとし、a = 1を返します。

「JavaScriptホイスト」に関するこの投稿を読むまで、私もこれについて混乱していました。http: //www.ufthelp.com/2014/11/JavaScript-Hoisting.html

それが役に立てば幸い。


0

これは、より多くの注釈と一緒に遊ぶためのフィドルを伴う、私の回答の要約です。

// hoisting_example.js

// top of scope ie. global var a = 1
var a = 1;

// new scope due to js' functional (not block) level scope
function b() {
    a = 10; // if the function 'a' didn't exist in this scope, global a = 10
  return; // the return illustrates that function 'a' is hoisted to top
  function a(){}; // 'a' will be hoisted to top as var a = function(){};
}

// exec 'b' and you would expect to see a = 10 in subsequent alert
// but the interpreter acutally 'hoisted' the function 'a' within 'b' 
// and in doing so, created a new named variable 'a' 
// which is a function within b's scope
b();

// a will alert 1, see comment above
alert(a);

https://jsfiddle.net/adjavaherian/fffpxjx7/


0

scpope&クロージャー&ホイスト(var / function)

  1. scpope:グローバル変数は任意の場所(ファイルスコープ全体)でアクセスでき、ローカル変数はローカルスコープ(関数/ブロックスコープ)でのみアクセスできます!
    注:関数でvarキーワードを使用していないローカル変数は、グローバル変数になります!
  2. クロージャ:他の関数の内部の関数で、ローカルスコープ(親関数)とグローバルスコープにアクセスできますが、変数には他の人がアクセスできません!そうでなければ、あなたはそれを戻り値として返します!
  3. 巻き上げ:値またはnullを割り当てるよりも、すべてのdeclare / undeclare vars / functionをスコープの上部に移動します!
    注:値を移動するのではなく、宣言を移動するだけです!

var a = 1;                
//"a" is global scope
function b() {  
   var a = function () {}; 
   //"a" is local scope 
   var x = 12; 
   //"x" is local scope 
   a = 10;
   //global variable "a" was overwrited by the local variable "a"  
   console.log("local a =" + a);
   return console.log("local x = " + x);
}       
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x = 
console.log(x);
// ReferenceError: x is not defined



0

JavaScriptにおけるホイストとは、コードが実行される前に、変数宣言がプログラム全体で実行されることを意味します。したがって、コード内の任意の場所で変数を宣言することは、最初に変数を宣言することと同じです。


0

そのすべては変数 'a'のスコープに依存します。スコープを画像として作成して説明します。

ここでJavaScriptは3つのスコープを作成します。

i)グローバルスコープ。ii)関数b()スコープ。iii)関数a()スコープ。

ここに画像の説明を入力してください

そのとき 'alert'メソッドスコープを呼び出すとグローバルに属しているため、グローバルスコープから変数 'a'の値が1だけ選択されます。


0

ロングポスト!

しかし、それは空気をきれいにします!

Java Scriptが機能する方法は、2つのステップからなるプロセスです。

  1. コンパイル(いわば)-この手順では、変数と関数の宣言、およびそれぞれのスコープを登録します。:これは、関数式の評価は含まれませんvar a = function(){}(割り当てるようにまたは変数表現を3xた場合にはvar x =3;何もなく、RHS部の評価ではありませんています。)

  2. 通訳:これは実行/評価の部分です。

以下のコードの出力を確認して、理解を深めます。

//b() can be called here!
//c() cannot be called.
console.log("a is " + a);
console.log("b is " + b);
console.log("c is " + c);
var a = 1;
console.log("Now, a is " + a);
var c = function() {};
console.log("Now c is " + c);

function b() {
  //cannot write the below line:
  //console.log(e); 
  //since e is not declared.
  e = 10; //Java script interpreter after traversing from this function scope chain to global scope, is unable to find this variable and eventually initialises it with value 10 in global scope.
  console.log("e is " + e) //  works!
  console.log("f is " + f);
  var f = 7;
  console.log("Now f is " + f);
  console.log("d is " + d);
  return;

  function d() {}
}
b();
console.log(a);

それを壊しましょう:

  1. コンパイルフェーズでは、「a」は値「undefined」でグローバルスコープの下に登録されます。同じことが ' c'にも当てはまります。この時点での値は ' undefined'であり、 ' function()'ではありません。' b'は関数としてグローバルスコープに登録されます。インサイドbの範囲、 " f「この時点で不定になり、変数や関数」として登録されるだろうd"登録されます。

  2. インタプリタが実行function()されると、インタプリタが実際の式の行に到達する前に、宣言された変数(および式ではない)にアクセスできます。したがって、変数は ' undefined'と表示され、宣言された無名関数を以前に呼び出すことができます。ただし、式の初期化前に宣言されていない変数にアクセスしようとすると、次のようなエラーが発生します。

console.log(e)
e = 3;

ここで、同じ名前の変数と関数の宣言があるとどうなりますか。

答えは -関数は常に前に巻き上げられ、同じ名前の変数が宣言されている場合、重複として扱われ、無視されます。順序は関係ありません。関数は常に優先されます。ただし、評価フェーズでは、変数の参照を何にでも変更できます(最後の割り当てであったものが保存されます)以下のコードを見てください。

var a = 1;
console.log("a is " + a);

function b() {
  console.log("a inside the function b is " + a); //interpreter finds                                'a' as function() in current scope. No need to go outside the scope to find 'a'.
  a = 3; //a changed
  console.log("Now a is " + a);
  return;

  function a() {}
}
var a; //treated as duplicate and ignored.
b();
console.log("a is still " + a + " in global scope"); //This is global scope a.


0

巻き上げはJavaScriptの動作概念です。巻き上げ(移動など)は、変数を宣言する方法と場所を説明する概念です。

JavaScriptでは、JavaScriptインタープリターによって関数宣言と変数宣言が常にそれらを含むスコープの最上部に見えないように移動(「巻き上げ」)されるため、変数は使用後に宣言できます。

ほとんどの場合、巻き上げには2つのタイプがあります。

1.Variable宣言の巻き上げ

このコードでこれを理解しましょう。

 a = 5; // Assign 5 to a
 elem = document.getElementById("demo"); // Find an element 
 elem.innerHTML = a;                     // Display a in the element
 var a; // Declare a
  //output-> 5

ここで、変数aの宣言は、コンパイル時にjavascriptインタープリターによって目に見えないようにホストされます。したがって、aの値を取得することができました。しかし、このように変数を宣言する必要があるため、この変数の宣言方法はお勧めできません。

 var a = 5; // Assign and declare 5 to a
 elem = document.getElementById("demo"); // Find an element 
 elem.innerHTML = a;                     // Display a in the element
  // output -> 5

別の例を考えてみましょう。

  function foo() {
     console.log(x)
     var x = 1;
 }

実際には次のように解釈されます:

  function foo() {
     var x;
     console.log(x)
     x = 1;
  }

この場合、xは未定義になります

変数の宣言を含むコードが実行されたかどうかは関係ありません。この例を考えてみましょう。

  function foo() {
     if (false) {
         var a = 1;
     }
     return;
     var b = 1;
  }

この関数は次のようになります。

  function foo() {
      var a, b;
      if (false) {
        a = 1;
     }
     return;
     b = 1;
  }

変数宣言では、代入ではなく変数定義ホイストのみが使用されます。

  1. 関数宣言の巻き上げ

関数本体または割り当てられた値を巻き上げる変数とは異なり、巻き上げられます。このコードを検討してください

 function demo() {
     foo(); // this will give error because it is variable hoisting
     bar(); // "this will run!" as it is function hoisting
     var foo = function () {
         alert("this would not run!!");
     }
     function bar() { 
         alert("this will run!!");
     }
 }
 demo();

変数と関数の両方の巻き上げを理解したところで、このコードを理解しましょう。

var a = 1;
function b() {
  a = 10;
  return;
   function a() {}
}
b();
alert(a);

このコードは次のようになります。

var a = 1;                 //defines "a" in global scope
 function b() {  
   var a = function () {}; //defines "a" in local scope 
    a = 10;                 //overwrites local variable "a"
    return;      
 }       
 b();       
 alert(a); 

関数a()は、b()内にローカルスコープを持ちます。a()は、コードとその定義を解釈している間(関数の巻き上げの場合のみ)、先頭に移動するため、aはローカルスコープを持つため、aのグローバルスコープに影響を与えず、関数b()内に独自のスコープを持ちます。


0

私の知識から、巻き上げは変数宣言と関数宣言で発生します。次に例を示します。

a = 7;
var a;
console.log(a) 

JavaScriptのエンジン内で何が起こるか:

var a;
a = 7;
console.log(a);
// 7

または:

console.log(square(7)); // Output: 49
function square(n) { return n * n; }

それは次のようになります:

function square(n) { return n * n; }
console.log(square(7)); // 49

ただし、変数の割り当て、関数式の割り当てなどの割り当ては解除されません。次に例を示します。

console.log(x);
var x = 7; // undefined

次のようになります。

var x;
console.log(x); // undefined
x = 7;

0

JavaScriptでのホスティングを1つの文で説明するのは変数であり、関数は宣言されているスコープの最上部まで引き上げられます。

ここに画像の説明を入力してください

私はあなたが初心者であることを前提としています。最初に適切に巻き上げを理解するために、未定義ReferenceErrorの違いを理解しました

 var v;
 console.log(v);
 console.log(abc);
/*
The output of the above codes are:
undefined
ReferenceError: abc is not defined*/

さて、次のコードでは何が見えるでしょうか?変数と関数式がクリアされます。

<script>
var totalAmo = 8;
var getSum = function(a, b){
      return a+b;
}
</script>

しかし、変数と関数の両方がスコープの上部に巻き上げられていることを証明する実際の画像:

console.log(totalAmo);
console.log(getSum(8,9));
var totalAmo = 8;
var getSum = function(a, b){
      return a+b;
}
console.log(totalAmo);
console.log(getSum(9,7));

最初の2つのログの出力は未定義TypeError例外:getSumは関数ではありません VARの両方のためtotalAmogetSumは怒鳴るようにその範囲の上に掲揚されています

 <script>
        var totalAmo;
        var getSum;

        console.log(totalAmo);
        console.log(getSum(8,9));
        var totalAmo = 8;
        var getSum = function(a, b){
            return a+b;
        }
        console.log(totalAmo);
        console.log(getSum(9,7));
    </script>

ただし、関数宣言の場合、関数全体がスコープの最上部に引き上げられます。

console.log(getId());
function getId(){
   return 739373;
}
/* output: 739373, because the whole function hoisted on the top of the scope.*/

これで、関数スコープ内で宣言された変数、関数式、関数宣言に同じロジックが適用されます。重要なポイント:それらはファイルの上部に巻き上げられません

function functionScope(){
            var totalAmo;
            var getSum;

            console.log(totalAmo);
            console.log(getSum(8,9));
            var totalAmo = 8;
            var getSum = function(a, b){
                return a+b;
            }
        }

したがって、varキーワードを使用すると、変数と関数がスコープ(グローバルスコープと関数スコープ)の上部に巻き上げられます。letconstはどうですか、constのと聞かせてちょうどVARのように、まだ両方のグローバルスコープと関数スコープを認識しているが、CONSTと変数はまた別のスコープを知っている聞かせてはブロックスコープと呼ばれます。ブロックスコープは、forループ、if elseステートメント、whileループなど、コードのブロックがある場合は常に存在します。

constを使用してこれらのブロックスコープで変数を宣言すると、変数の宣言は、そのブロックが含まれているそのブロックの上部でのみ巻き上げられ、親関数の上部または巻き上げられるグローバルスコープ。

 function getTotal(){
            let total=0;
            for(var i = 0; i<10; i++){
                let valueToAdd = i;
                var multiplier = 2;
                total += valueToAdd*multiplier;
            }
            return total;
        }

abobeの例の変数は、次のように巻き上げられます

 function getTotal(){
            let total;
            var multiplier;
            total = 0;
            for(var i = 0; i<10; i++){
                let valueToAdd;
                valueToAdd = i;
                multiplier = 2;
                total += valueToAdd*multiplier;
            }
            return total;
        }

0

ES5:関数の巻き上げと変数の巻き上げ

function hoisting優先順位があるgreaterよりも、variable hoisting

"use strict";

/**
 *
 * @author xgqfrms
 * @license MIT
 * @copyright xgqfrms
 * @created 2016-06-01
 * @modified
 *
 * @description function-hoisting.js
 * @augments
 * @example
 * @link
 *
 */

(function() {
  const log = console.log;

  var a = 1;
  function b() {
    a = 10;
    log(`local a`, a)
    return;
    // function hoisting priority is greater than variable hoisting
    function a() {}
  }
  b();
  log(`global a`, a);
  // local a 10
  // global a 1
})();


に等しい

(function() {
  const log = console.log;

  // define "a" in global scope
  var a = 1;
  function b() {
    // define "a" in local scope
    var a ;
    // assign function to a
    a = function () {};
    // overwrites local variable "a"
    a = 10;
    log(`local a`, a);
    return;
  }

  b();
  // log global variable "a"
  log(`global a`, a);

  // local a 10
  // global a 1
})();

巻き上げの背後にある理由

var a = 1;                
//"a" is global scope
function b() {  
   var a = function () {}; 
   //"a" is local scope 
   var x = 12; 
   //"x" is local scope 
   a = 10;
   //global variable "a" was overwrited by the local variable "a"  
   console.log("local a =" + a);
   return console.log("local x = " + x);
}       
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x = 
console.log(x);
// ReferenceError: x is not defined

/**
 *  scpope & closure & hoisting (var/function)
 *  
 * 1. scpope : the global var can be access in any place(the whole file scope), local var only can be accessed by the local scope(function/block scope)!
 * Note: if a local variable not using var keywords in a function, it will become a global variable!
 * 
 * 2. closure : a function inner the other function, which can access local scope(parent function) & global scope, howerver it's vars can't be accessed by others! unless, your return it as return value!
 * 
 * 3. hoisting : move all declare/undeclare vars/function to the scope top, than assign the value or null!
 * Note: it just move the declare, not move the value!
 * 
 */

ES6 letconst巻き上げなし

(() => {
  const log = console.log;
  log(a)
  // Error: Uncaught ReferenceError: Cannot access 'a' before initialization
  let a = 1;
})();


(() => {
  const log = console.log;
  log(b)
  // Error: Uncaught ReferenceError: Cannot access 'b' before initialization
  const b = 1;
})();

refs

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.