JavaScriptではHoisting (巻き上げ)が起きます。
巻き上げとは
関数や変数をコードが実行する前にメモリに格納すること
関数宣言の場合
func(); //ジョジョ
function func() {
console.log("ジョジョ");
};
上記のコードのように呼び出しが定義より前でも実行可能なのは関数が巻き上げられてるからです。
巻き上げが起きることでfuncという関数が呼び出しより先に定義されてると認識されます。
//巻き上げられるので関数宣言が呼び出しより先に読み込まれる
function func() {
console.log("ジョジョ");
};
func(); //ジョジョ
なので関数宣言の場合は呼び出しが先に来ても実行されます。
今度は変数の巻き上げを見てみましょう。
変数の場合
var myname = "空条承太郎"
function func() {
console.log(myname);
}
func(); //"空条承太郎"
"空条承太郎" と出るのが分かりますよね
以下の場合どうでしょうか?
var myname = "空条承太郎";
function func() {
console.log(myname);
var myname = "吉良吉影";
console.log(myname);
}
func();
3行目で"空条承太郎"、5行目で"吉良吉影"が出力されそうですよね。
実際に試してみましょう。
var myname = "空条承太郎";
function func() {
console.log(myname); //undefined
var myname = "吉良吉影";
console.log(myname); //吉良吉影
}
func();
undefinedと"吉良吉影"が出力されます。これが巻き上げです。
関数内で宣言されたローカル変数は、すべてその関数の先頭で宣言されたものとみなされます。
//上記のコードは以下のコードと同じ振る舞いになる
var myname = "空条承太郎";
function func() {
var myname; // 宣言した段階でundefinedが格納される
console.log(myname); //undefinedが出力される
myname = "吉良吉影"; //初期化される(代入)
console.log(myname); //吉良吉影が出力される
}
func();
letで試してみる
//エラーになる
let myname = "空条承太郎";
function func() {
console.log(myname);
let myname = "吉良吉影";
console.log(myname);
}
func(); //Uncaught ReferenceError: Cannot access 'myname' before initialization
constでも実行
//エラーになる
const myname = "空条承太郎";
function func() {
console.log(myname);
const myname = "吉良吉影";
console.log(myname);
}
func(); //ReferenceError: Cannot access 'myname' before initialization
varだとundefindが出力されますが(エラーではない)const、letだとReferenceErrorとして扱われます(処理が止まる)
undefindはエラーではないので処理が止まりません、なのでバグの温床になるのかなと思いました!