#はじめに
Udemyの【JS】ガチで学びたい人のためのJavaScriptメカニズムの講座の振り返りです。
前回の記事
#目的
- スコープについての理解を深める
#本題
###1.レキシカルスコープ
コードを書く場所によって参照できる変数が変わるスコープのことです。
実行中のコードからみた外部スコープのことという意味もある。
// aを定義する(スクリプトスコープ)
let a = 2;
// 関数fn1を定義(スクリプトスコープ)
function fn1(){
// 関数fn1の中に変数bと関数fn2を定義(関数スコープ)
let b = 1;
console.log(b);
function fn2(){
// fn2の中に変数cを定義
let c = 3;
}
// ここでfn2を実行するとa,b,fn1を参照できる
fn2();
}
// ここでfn1を実行するとaを参照できる
fn1();
// スクリプトスコープはどこからでも参照可能 => 変数aはどこでも参照可
// 自身のスコープより外部のスコープを参照できる
###2.スコープチェーン
**スコープが複数階層で連なっている状態(上記レキシカルスコープの例)**のこと
例
let a = 2;
function fn1(){
let a = 1;
function fn2(){
// fn1,fn2で同じ変数aを定義し出力する
// ブラウザで確認すると「3」と表示される
let a = 3;
console.log(a);
}
fn2();
}
fn1();
続いて、let a = 3をコメントアウトすると下記のようになります。
let a = 2;
function fn1(){
let a = 1;
function fn2(){
// もしここで下記をコメントアウトすると
// let a = 3;
console.log(a);
}
fn2();
}
fn1();
// a = 1という値が出力される
// スコープが複数階層になっている場合には1つずつ外側に同じ変数がないか探しにいく
// 見つかった時点で、その変数を参照する
````
次はグローバルスコープとスクリプトスコープに同じ変数名がある場合について考えていきます。
```javascript
// スクリプトスコープ
let a = 2;
// グローバルスコープ
window.a = 4;
function fn1(){
// let a = 1;
function fn2(){
// let a = 3;
console.log(a);
}
fn2();
}
fn1();
// この場合実行結果はa = 2が出力される
// グローバルスコープはスクリプトスコープより外側のスコープであるということがわかる
// 内側のスコープから探しに行く = 見つからない場合にエラーにな
```
よく間違える例
let a = 3をconsole.logより下に定義した場合どうなるのか
```javascript
// スクリプトスコープ
let a = 2;
// グローバルスコープ
window.a = 4;
function fn1(){
// let a = 1;
function fn2(){
console.log(a);
let a = 3;
}
fn2();
}
fn1();
// main.js:8 Uncaught ReferenceError: Cannot access 'a' before initializationというエラーが発生
// letを使った変数宣言より前に値を取得しようとするとエラーになる
```
もしもletではなくvarだったら
```javascript
// スクリプトスコープ
let a = 2;
// グローバルスコープ
window.a = 4;
function fn1(){
// let a = 1;
function fn2(){
console.log(a);
if (true){
var a = 3;
}
// var = 3;のホスティングが働いてしまうのでundifinedと出力される
// ホスティングとはコンテキスト内で宣言した変数や関数の定義をコード実行前にメモリーに配置すること
}
fn2();
}
fn1();
````
今日はここまで!
#参考にさせて頂いた記事
* [【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)