【js】ver,let,constの違いとスコープ範囲

結論

原則 var は使わない
変数宣言は基本的に const で
変数への再代入が必要な場合に限り let を使う

基本的に変数は const で宣言し、再代入が必要な変数のみ let を使う。
さらにどうしても var が必要なケースのみ var で宣言する、というのがベストプラクティス。
上書されたくない変数をわざわざ var や let で宣言する必要はないでしょう。また、const で宣言された変数は再代入されることが無いので、変数の内容を追跡する必要が無いということはデバッグ時の負担を軽減してくれるというメリットもある。

ver

再宣言:OK
再代入:OK
スコープ:関数スコープ

<script>
    //==関数1==
    var test = function(){
      var greet = 'こんにちは';
      console.log(greet); // 'こんにちは'
      
      //再宣言
      var greet = 'Hello';
      console.log(greet); // 'Hello'
      
      //再代入
      greet = 'アニョハセヨ';
      console.log(greet); // 'アニョハセヨ'
      
      //関数内のif文など
      if(true){
        console.log(greet); // 'アニョハセヨ'
        greet = 'ニーハオ';
  var name = '鈴木さん';
      }
      
      console.log(greet); // 'ニーハオ'
      console.log(name); // '鈴木さん'
    }


    //==関数2==
    var test2 = function(){
      console.log(greet); // not defined
    }

test();
test2();
</script>

【解説】
varの再宣言や再代入ができてます。
関数スコープなので、関数内を1つの行動範囲としているので、その関数内であればif文で囲って使用したり、再宣言、再代入しもOK。
(varは、関数内であれば細かいブロックは仕切りとして認識しない)

ただし、関数スコープなので、関数から外には出れない。
よって、別の関数2では、エラーになる。


let

再宣言:NG
再代入:OK
スコープ:ブロックスコープ

<script>
    //==関数1==
    let test = function(){
      let love = '月が綺麗ですね';
      console.log(love); //'月が綺麗ですね'

      //再宣言
      let love = 'I love you';
      console.log(love); //'月が綺麗ですね' ※再宣言しても値は変わらない

      //再代入
      love = 'サランヘヨ';
      console.log(love); //'サランヘヨ' ※再代入はできる

      if(ture){
        console.log(love); //'サランヘヨ'
        love = '我爱你';
        let name = '田中さん';
      }

      console.log(love); //'我爱你'
      console.log(name); // not defined
    }
     
     //==関数2==
     let test2 = function(){
     console.log(love); // not defined
    }

test();
test2();

</script>

【解説】
同じ変数名で再宣言をするとエラーになる。
ブロックスコープなので、ブロック(if文やfor文など)内が行動範囲になる。
loveが宣言されたブロックから見ると、if文も自分のブロック内のため、使えるし、再代入もできる。
逆に、if文を見てわかるように、関数内であれば仕切りを気にしないvarとは異なり、letは仕切りをブロック単位にするため、fi文内で新しく宣言されたnameは、if文内でしか行動することができない。

当然、別のブロックの関数2では、エラーになる。

const

再宣言:NG
再代入:NG
スコープ:ブロックスコープ

<script>
    //==関数1==
    const test = function(){
      const good = '元気ですか?';
      console.log(good); //'元気ですか?'

      //再宣言や再代入
      let love = 'how are you?';
      love = 'how are you?';
      console.log(good); //'元気ですか?' ※再宣言しても再代入しても値は変わらない

      if(ture){
        console.log(good); //'元気ですか?'
        const name = '渡辺さん';
      }

      console.log(name); // not defined
    }
     
     //==関数2==
     let test2 = function(){
     console.log(good); // not defined
    }

test();
test2();

</script>

【解説】
再宣言も再代入もNG。
スコープ範囲は、let参照。

constの値は絶対に不変??

たしかにconstの値を直接再代入して変更することはできません。ただし、オブジェクトを操作することはできます。

<script>
//オブジェクトだ代入されている
const PLAYER = {name: "渡辺", age:"24", sex:"female"};

// NG (constに直接再代入しているのでエラーになる)
const PLAYER = {name: "中村", age:"30", sex:"male"};

// OK (オブジェクトを操作しているので間接的にconstの値を変更できる)
PLAYER.name = "中村";
PLAYER.age = 30;
PLAYER.sex = "male";

// PLAYER定数のオブジェクト➡ {name: "中村", age:"30", sex:"male"}; に変わる!!
</script>

javascript特有POINT!!
javascriptにおける連想配列とオブジェクトの違い

変数の巻き上げ

以下は、1つ目のXは、0ではなく、undefinedが表示されます。
JavaScriptは関数が宣言された時、その関数内でvarで宣言されてるすべての変数を、勝手に関数の一番上でundefinedで初期化します。

<script>
 var x = 'ハンバーガー';
    let test = function (){
        console.log(x); // undefined

        var x = '餃子';
        console.log(x); // '餃子'
    }
test();
</script>

↓ 起きてる現象:★部分が実装されている

<script>
 var x = 'ハンバーガー';
    let test = function (){
    var x; //    ★ ・・・ var x=undefined; この処理が入る
        console.log(x); // undefined

        var x = '餃子';
        console.log(x); // '餃子'
    }
test();
</script>

【解説】
・letとconstを使う。
・関数内で宣言する変数はなるべく、関数内の先頭に記述する。

参考URL
https://qiita.com/wannabe/items/b2a0d63fc786eab13c48qiita.com