javascriptをudemyで学んでみた（スコープ編）

udemyの[ガチで学びたい人のためのJavascriptメカニズム](https://www.udemy.com/course/javascript-essence )という講座を受講しまして、
自分の言葉でまとめたいなと思ったのでこの記事を書きました。

最近エンジニアになったばかりですので暖かい目で見ていただければと思います

記事の中に **「自分の解釈」** という項目を記述している箇所があります
厳密にはその解釈が少し違う場合があるかもしれないので、その場合は突っ込んでいただけると嬉しいです


# jsを学ぶ理由
シンプルに「Reactを使ってみたいなー」と思ったからです
しかし、どうやらReactを使うにはjsの基礎がわかっていないと話にならんとのことだったので、とりあえず素のjsしっかり学ぼうと思いました。教材に触れる前の自分のレベル感としては「プログラミングの基礎はある程度わかる」「DOM操作も何となくわかる」「非同期処理はJQueryを使ってならやったことある」です

ちなみに知らなかった用語としては「スコープ」「クロージャー」「モジュール」などです
（スコープに関しては今まで意識して使ったことがないというのが正しいかもです）

# Reactに必要な知識
[こちら](https://dev-k.hatenablog.com/entry/react-top_skill-_ist-of-javascript )の記事を参考してに学ぶ項目を決めました
キーワードをざっと羅列するとスコープ、モジュール、非同期処理、スプレッド演算子、三項演算子、ES6クラス etc...

# この教材のレベル感
正直なかなか難しいです
メモリレベルでのお話や、ブラックボックスになっている処理をあえて解き明かしたりと、
とても深い領域まで解説されています

一応講座自体は全て目は通しているのですが、自分の目的はあくまでReactなのでとても難しくて重要度が高くないと判断した箇所に関しては、後で出てきた際に **「あ、なんか見たことある〜」** 程度の理解で十分かなと思っています

ですので、「そこまではいらんかな〜」と感じたところはバリバリ端折るので許してください


# スコープってなんだ？
スコープとは　**「実行中のコードから値と式が参照できる範囲」** のことだそうです
グローバルスコープ、スクリプトスコープ、関数スコープ、ブロックスコープ、モジュールスコープの合計５種類のスコープがあるらしい（モジュールスコープは別の記事で触れる予定ですので、今回はカットしました）　

### グローバルスコープとスクリプトスコープ
windowオブジェクト＝グローバルスコープ

**プログラム中でどこからでも有効な変数の範囲を表したもの** という認識でOK
一般的にはスクリプトスコープはグローバルスコープも同じみたいなので、そんなに意識する必要はないんだそう


```javascript:qiita.js
// グローバルスコープ
let a = 1;
const b = 'むきむき';

function a(){
   
}

```

### 関数スコープとブロックスコープ
##### 自分の解釈 ↓
**「関数を宣言した際の{}の領域とただの{}の中の領域」** という感じです

```javascript:qiita.js
function a(){
// 関数スコープ
}

{
//ブロックスコープ
}
```

また、ブロックスコープ内で変数宣言を行う場合はletとconstを使う必要があります
varを使うとブロックスコープが生成されず、{}の外部でも変数が使えてしまうので注意しないといけないです

*ちなみにvarは非推奨となっているのでもう使わない方が良い

```javascript:qiita.js
{
    let a = 0;
    const b = 1;

    var c = 2;
}

console.log(a); //エラー！
console.log(b); //エラー！

console.log(c); 2 
```



そして、ブロックスコープ内で関数宣言において関数を生成した場合においても、ブロックスコープの外側でも使えてしまうといったことが起こります
これを解決するためには関数を関数式で生成してあげることです

```javascript:qiita.js
//関数宣言の場合
{
    function a(){
        console.log('パワーーー！！！');
    }
}

a(); //パワーーー！！！

// 関数式の場合
{
    const a = function () {
        console.log('ヤー');
    }
}

a(); // エラー！　←これでいい
```


### レキシカルスコープ
さて、今回の一番の勉強ポイントがこちらのレキシカルスコープでした

講座の中では　**「実行中のコードから見た外部のスコープのこと」**　または **「どのようにしてスコープを決定するかの仕様のこと」** という２つの説明がありました。

##### 自分の解釈はこんな感じ ↓

前者はそのままの意味で、関数fn2から見たfn１のスコープのこと

```javascript:qiita.js
let a = 2;
function fn1() {
    // ① 
    let b = 1;

    function fn2() {
        //　ここから①を見た場合①を外部スコープという
        let c = 3;
        console.log(b);
    }
    fn2();
}
fn1();
```

後者の意味は、 **「コードを書く場所によって参照できる変数が変わるもの」** という認識で大丈夫だと思います
ちなみにコードを記述した時点でスコープが決定するため **「静的スコープ」** ともいわれるそう

以下のコードだとスコープ外となりエラーとなります
当たり前ですね
```javascript:qiita.js
let a = 2;
function fn1() {
    let b = 1;
}
fn1();

function fn2() {
    let c = 3;
    console.log(b);//fn１のスコープ外なのでエラー
}
fn2();
```
### スコープチェーン
スコープチェーンとはスコープが複数階層で連なっている状態のこと

##### こんな感じ ↓（fn1のスコープ内にfn2のスコープがある）

```javascript:qiita.js
let a = 2;
function fn1() {
    let b = 1;
    function fn2() {
        let c = 3;
        console.log(b);
    }
    fn2();
}
fn1();
```
console.log(b)が実行された時の流れはこんな感じ

①関数fn2のconsole.logは初めにfn2の関数スコープ内で変数bを探します
②その次に、その外部であるfn1のスコープ内に探しに行きます
③この例ではfn1の関数スコープ内に変数bが宣言されているのでこちらの値が使用されます
④もしfn1にもない場合は、グローバルスコープまで探しに行きます
⑤もし、グローバルスコープ内でも見つからない場合はここでエラーとなります

# クロージャー
クロージャーとはレキシカルスコープの変数を関数が使用している状態のこと

クロージャーを用いることで **プライベートな変数の生成** と **動的な関数の生成** が可能になります
### プライベートな変数
プライベートな変数とは言い換えると **外部のスコープからアクセスできない変数** のことです


```javascript:qiita.js
function incrementFactory() {
    
    let num = 0;

    function a() {
        num = num + 1;
        console.log(num);
    }

    return a;
}

const increment = incrementFactory();

increment();

```

let num = 0に注目するとこの変数は関数incrementFactoryのスコープ内で宣言されているため、外部のスコープからこの変数が使用されることはなくなります。もしincrementFactoryがない場合は変数numはさまざまなとこから自由にアクセスすることが可能になってしまいます。それを防ぐために外側をあえて関数で囲むことによって、プライベートな変数の作成を可能にしているのです。

### 動的な関数
以下のaddNumberFactoryに渡す実引数に注目してください

```javascript:qiita.js
function addNumberFactory(num) {
    function addNumber(value) {
        return num + value;
    }
    return addNumber;
}

const add5 = addNumberFactory(5); //←これ
const add10 = addNumberFactory(10);//←これ

const result5 = add5(10);
const result10 = add10(10);

console.log(result5); // 15
console.log(result10); // 20
```
実引数の値が変わると、生成される関数が変わることから動的な関数が生成されているといえます。
これもクロージャーの恩恵を受けている例の一つですね

# 終わりに
今回はスコープ編として学習したことをまとめました。
次回は関数についてまとめたいと思います

キーワードとしては、コールバック関数、アロー関数、bind、apply、callです

## 教材以外に参考にした記事
https://atmarkit.itmedia.co.jp/ait/articles/0708/21/news116_2.html