簡単な例でスコープを理解
const x = 3;
function f(){
console.log(x); //3
console.log(y); // y is not defined (error)
}
f();
const y = 5;
x : 関数を呼ぶ出す前に存在している →関数にも使える
y : 関数を呼び出した後に存在している → 定義前に呼び出された関数には使えない
スコープ : 変数を参照できる範囲
グローバルスコープ
グローバルスコープは全てのプログラム内で使用可能になる!!!
グローバルスコープで定義された変数をグローバル変数と呼ぶ!
しかし!
グローバル変数を濫用しすぎると、かなり困るから注意。。。
let name = "makoto";
let age = 19;
function greet(){
console.log(`こんにちは、${name}`); //makoto
}
function ageVerification(){
console.log(`私の年齢は、${age}です`); //19
}
トップにlet name / let age
を定義することで、それ以下に記述している関数に影響してくる(プログラム中のどこで定義された関数でもname/ageの値を変更できてしまう)
それは避けたいので、オブジェクトを使用して改善していく
let user = {
name : "makoto",
age : 19
};
function greet(user){
console.log(`こんにちは、${user.name}`) //makoto
}
function ageVerification(user){
console.log(`私の年齢は、${user.age}です`); //19
}
greet(user); //makoto
このように記述することで、よく使われるname
などの識別子をなどもグローバル変数にせずに使用することができる。
グローバル変数:name/age → user
ブロックスコープ
{ //ブロックスコープ開始
const x = 5;
console.log(x); //5
} //ブロックスコープ終了
console.log(x); //x is not defined
ブロックで囲むことで、ブロック内で定義した変数の値はブロック内でしか効力がない
クロージャー
独立した変数を参照する関数
let f;
{ //ブロックスコープ
let o = {name : "makoto", age : 19};
f = function(){ //スコープ内で関数を定義すると関数がスコープを保持する(スコープ内を参照する覗き窓)
console.log(o.name); //makoto
return o;
}
} //ブロックスコープ
let oRef = f(); //oオブジェクトを参照する変数を定義
console.log(oRef);{name:"makoto"}
oRef.name = "keigo"; //関数(のぞき窓)越しにスコープ内の値を変更!
console.log(oRef);{name:"keigo"}
通常は外部からスコープにアクセスできないが、関数を定義することで覗き窓を作ることができる!
関数の巻き上げ
f(); // "呼び出せた!"
function f(){
console.log("呼び出せた!")
}
関数宣言の場合、関数より先に関数の呼び出しを記述していても、関数の巻き上げで呼び出すことができる!
f(); // f is not defined
let f = function(){
console.log("呼び出せた!")
}
変数に代入すると、巻き上げは効かなくなる
TDZ(temporal dead zone)
console.log(x); //undefind
var x = 5;
console.log(x); //5
console.log(x); //x is not defined
let x = 5;
console.log(x); //
つまり、var
は宣言した瞬間にプログラム全体で存在していることになる
なので、undefined
と表示された
let
は、定義されたそれ以降から存在することになるのでこのような結果になる。(letで宣言された変数は宣言されるまで存在しない)