技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

JavaScript:未宣言・var・letの変数の挙動の違い

JavaScriptにおける変数の宣言方法は、constを除くと以下の4つがあります。
 
・未宣言
 var1 = "var1";
 のように、値が代入された時点で変数が宣言されたものとみなされる。
 
・var
 var var1;
 のように、var句により変数を宣言する。
 
・var(巻き上げ)
 var1 = "var1";
 var var1;
 のように値が代入された後にvarにより変数が宣言された場合、
 変数が宣言された後に値が代入されたものとみなされる。
 この例では、以下と同価とみなされる。
 var var1;
 var1 = "var1";
 
・let
 let var1;
 のように、var句により変数を宣言する。
 ES6のバージョン以降でサポートされている。
 
これらの宣言方法の違いにより、非Strictモードの場合に以下の挙動の違いが生じます。
(varの巻き上げについては、巻き上げしなかった場合と同じです)

f:id:akira2kun:20210807165734j:plain
 
なお、Strictモード(https://cyzennt.co.jp/blog/2021/04/01/javascript%EF%BC%9Astrict%E3%83%A2%E3%83%BC%E3%83%89%E3%81%A8%E3%81%AF/)の場合は、varやletやconstを用いて宣言をせずに変数に値を代入した場合にReferenceErrorで異常終了するようになります。
 
----
 
以下、挙動を確認するためのサンプルコードです。
(Node.jsで確認します)
 
それぞれの変数で以下を確認します。
 
・var1
 ブロック外で宣言した変数をブロック内でも宣言。
 ブロック内の変更がブロック外に影響するなら、
 ブロックを出た時点で変数が書き変わる。
 
・var2
 ブロック内でのみ変数を宣言。
 ブロック内の変更がブロック外に影響するなら、
 ブロックを出た時点で参照不可になる。
 
・var3
 関数内でのみ変数を宣言。
 関数内の変更が関数外に影響するなら、
 関数を出た時点で参照不可になる。
 
【テストコード(未宣言)】
・test.js
var1 = "var1";
console.log("before change :" + var1);

if (true) {
  var1 = "var1mod"
  var2 = "var2";
  console.log("in block    :" + var2);
}
console.log("after change  :" + var1);
console.log("out of block  :" + var2);

function func() {
  var3 = "var3";
  console.log("in function  :" + var3);
  return var3;
}
func();
console.log("out of function:" + var3);
 
【実行結果(未宣言)】
c:\tmp>node test.js
before change :var1
in block    :var2
after change  :var1mod
out of block  :var2
in function  :var3
out of function:var3

c:\tmp>
 
【テストコード(var)】
・test.js
var var1 = "var1";
console.log("before change :" + var1);

if (true) {
  var var1 = "var1mod"
  var var2 = "var2";
  console.log("in block    :" + var2);
}
console.log("after change  :" + var1);
console.log("out of block  :" + var2);

function func() {
  var var3 = "var3";
  console.log("in function  :" + var3);
  return var3;
}
func();
// console.log("out of function:" + var3); // ReferenceError
 
【実行結果(var)】
c:\tmp>node test.js
before change :var1
in block    :var2
after change  :var1mod
out of block  :var2
in function  :var3

c:\tmp>
 
【テストコード(var巻き上げ)】
・test.js
var1 = "var1";
var var1;
console.log("before change :" + var1);

if (true) {
  var1 = "var1mod"
  var var1;
  var2 = "var2";
  var var2;
  console.log("in block    :" + var2);
}
console.log("after change  :" + var1);
console.log("out of block  :" + var2);

function func() {
  var3 = "var3";
  var var3;
  console.log("in function  :" + var3);
  return var3;
}
func();
// console.log("out of function:" + var3); // ReferenceError
 
【実行結果(var巻き上げ)】
c:\tmp>node test.js
before change :var1
in block    :var2
after change  :var1mod
out of block  :var2
in function  :var3

c:\tmp>
 
【テストコード(let)】
・test.js
let var1 = "var1";
console.log("before change :" + var1);

if (true) {
  let var1 = "var1mod"
  let var2 = "var2";
  console.log("in block    :" + var2);
}
console.log("after change  :" + var1);
// console.log("out of block  :" + var2); // ReferenceError

function func() {
  let var3 = "var3";
  console.log("in function  :" + var3);
  return var3;
}
func();
// console.log("out of function:" + var3); // ReferenceError
 
【実行結果(let)】
c:\tmp>node test.js
before change :var1
in block    :var2
after change  :var1
in function  :var3

c:\tmp>