【JavaScript】varとletのスコープについて調べてみた
Javascriptでの変数の定義方法にはvar、let、constの3つがあります。この中でもvarとletの使い方で、ちょっと前に実装で先輩から「これはバグになる可能性がある」と注意を受けたので、備忘録として書き残そうと思います。
2つの違い
varとletの違いは2つあります。「使用できる範囲(スコープ)」です。今回は「分岐(if)」「ループ(for)」「例外処理(try~catch)」「関数(function)」の4つについて、内部で変数を定義した場合にどのような動きになるかを見てみましょう。
分岐(中で定義)
if文内で変数の定義し、if文の中と外で参照してみます。
var
if文の中にvarで変数定義すると、外でも使えます。
if (true) {
var test = "moji";
console.log("test1 = " + test);
}
console.log("test2 = " + test);
// -->
// test1 = moji
// test2 = moji
let
if文の中にletで変数定義すると、外では使えずエラーになります。
if (true) {
let test = "moji";
console.log("test1 = " + test);
}
console.log("test2 = " + test);
// -->
// test1 = moji
// Uncaught ReferenceError: test is not defined
分岐(後に定義)
if文の後で変数の定義し、if文の中と外で参照してみます。
var
if文の中にvarで変数定義すると、外でも使えます。
if (test) {
test = 'moji';
console.log("test = " + test);
} else {
console.log("test = " + test);
}
var test;
// --> test = undifined.
let
if文の中にletで変数定義すると、外では使えずエラーになります。
if (test) {
test = 'moji';
console.log("test = " + test);
} else {
console.log("test = " + test);
}
let test;
// --> Uncaught ReferenceError: Cannot access 'test' before initialization
ループ(中で定義)
for文の中でも変数を定義をしてみます。中と外でどのように参照できるでしょうか。
var
for文の中にvarで変数定義すると、外でも使えます。
for (let n = 0; n < 2; n++) {
var test = "moji";
console.log("test1 = " + test);
}
console.log("test2 = " + test);
// -->
// test1 = moji
// test1 = moji
// test2 = moji
let
for文の中にletで変数定義すると、外では使えずエラーになります。
for (let n = 0; n < 2; n++) {
let test = "moji";
console.log("test1 = " + test);
}
console.log("test2 = " + test);
// -->
// test1 = moji
// test1 = moji
// Uncaught ReferenceError: test is not defined
ループ(条件内で定義)
ループでの条件で使用する変数についても試してみます。
var
for文の条件でvarの変数定義すると、外でも使えます。
for (let n = 0; n < 2; n++) {
var test = "moji";
console.log("test1 = " + test);
}
console.log("test2 = " + test);
// -->
// test1 = moji
// test1 = moji
// test2 = moji
let
for文の条件でletの変数定義をすると、外では使えずエラーになります。
for (let n = 0; n < 2; n++) {
let test = "moji";
console.log("test1 = " + test);
}
console.log("test2 = " + test);
// -->
// test1 = moji
// test1 = moji
// Uncaught ReferenceError: test is not defined
例外処理(中で定義)
try~catch文でも同様に内部で定義してみて、その外で参照してみます。
var
tryの中にvarで変数定義すると、外でも使えます。しかし、上記では入っていませんが、testの定義前で例外が発生すると、変数が定義されていないためtest2の出力でエラーになります。
try {
var test = "moji";
console.log("test1 = " + test);
} catch (err) {
console.log("error: " + err.message);
}
console.log("test2 = " + test);
// -->
// test1 = moji
// test2 = moji
let
tryの中にletで変数定義すると、外では使えずエラーになります。
try {
let test = "moji";
console.log("test1 = " + test);
} catch (err) {
console.log("error: " + err.message);
}
console.log("test2 = " + test);
// -->
// test1 = moji
// Uncaught ReferenceError: test is not defined
関数(中で定義)
function関数の内部でも変数の定義を行い、外部で参照してみます。
var
functionの中にvarで変数定義すると、外では使えずエラーになります。
function testFunc() {
var test = "moji";
console.log("test1 = " + test);
}
testFunc();
console.log("test2 = " + test);
// -->
// test1 = moji
// Uncaught ReferenceError: test is not defined
let
functionの中にletで変数定義すると、外では使えずエラーになります。
function testFunc() {
let test = "moji";
console.log("test1 = " + test);
}
testFunc();
console.log("test2 = " + test);
// -->
// test1 = moji
// Uncaught ReferenceError: test is not defined
まとめ
上記の内容をまとめると以下のようになります。内部で定義した場合、外でも使用できるときは「〇」、外では使えずエラーが発生する場合は「✕」で示します。
文法 定義位置 var let 分岐(if) 内部 〇 ✕ 分岐(if) 外部 〇(ただしundifined) ✕ ループ(for) 内部 〇 ✕ ループ(for) 条件文 〇 ✕ 例外処理(try~catch) 内部 〇 ✕ 関数(function) 内部 ✕ ✕
この結果から、関数以外の内部でvarを使用した変数定義を行わない方がよいことがわかります。varを使った場合、外部で上書きができてしまうため、注意です。条件文やループ文内で変数定義する場合はletを使うことをお勧めします。
個人的にはちゃんと違いも分からず使用していた節がありました。基本的はletを使用したいと思います。