目次
スコープチェーンとは
スコープチェーンの定義
スコープが複数階層で、連なっている状態。下記画像の状態。
スコープが複数階層になっている場合は、一番内側から変数を探しに行き、見つかった段階でその変数を取得する。
// 下記の場合、3が表示される
let a = 1;
function fn1() {
let a = 2;
function fn2() {
let a = 3;
console.log(a);
}
fn2();
}
fn1();
// 下記の場合、1が表示される
let a = 1;
function fn1() {
// let a = 2;
function fn2() {
// let a = 3;
console.log(a);
}
fn2();
}
fn1();
グローバルスコープとスクリプトスコープの場合
グローバルスコープは、スクリプトスコープより外側のスコープ。
// a = 2が出力される
let a = 2; // スクリプトスコープ
window.a = 4; // グローバルスコープ
function fn1() {
function fn2() {
console.log(a);
}
fn2();
}
fn1();
スクリプトスコープで起きやすいミス
// 下記の場合、letを使った変数より前に値を取得しようとしているので、エラーが発生する
let a = 2;
window.a = 4;
function fn1() {
function fn2() {
console.log(a);
let a = 3;
}
fn2();
}
fn1();
letの場合はエラーが出るのでまだわかりやすい。
varの場合で、if文などブロックで囲まれているときに、varのホイスティングが働いてしまうため、aはundefinedとなる。
let a = 2;
window.a = 4;
function fn1() {
function fn2() {
console.log(a);
if (true) {
var a = 3;
}
}
fn2();
}
fn1();
クロージャーとは
クロージャーの定義
レキシカルスコープの変数を関数が使用している状態。
内側に定義されている関数から、レキシカルスコープの変数への参照を保持している状態をクロージャーという。
// 関数f2から、変数bに対してレキシカルスコープの値を参照しに行っている。
function fn1() {
let b = 3;
function fn2() {
console.log(b);
}
fn2();
}
fn1();
クロージャーを使用した関数の記述
- プライベート変数の定義
- 動的な関数の生成
プライベート変数の定義
【実装】 値がカウントアップされる仕組みを作る
increment();
increment();
increment();
function increment() {
let num = 0;
num = num + 1;
console.log(num);
}
// 関数の中でnumを宣言しているため、常にnumが0となる。結果、1が3回表示される
関数が呼ばれるたびではなく、グローバルコンテキストが実行されるタイミングで初期化を行う。
let num = 0;
increment();
increment();
increment();
function increment() {
num = num + 1;
console.log(num);
}
// 1 2 3と表示される。が、この状態ではnumの変更が可能となっている。
関数の内部に変数を持ちながらも、外部からはアクセスできないようにしたい。
function incrementFactory() {
let num = 0;
function increment() {
num = num + 1;
console.log(num);
}
return increment; // incrementをincrementFactoryへ返却
}
const increment = incrementFactory(); // incrementFactoryの実行
increment();
increment();
increment();
関数の外側からはnumにアクセスすることができないため、書き換えられる心配がない。
numの初期化はincrementFactoryが実行されたタイミングでのみ行われる。
動的な関数の生成
異なる結果を返す関数を動的に作成することができる。
function addNumberFactory(num) {
function addNumber(value) {
return num + value;
}
return addNumber;
}
const add5 = addNumberFactory(5);
const result = add5(10);
console.log(result);
解説
const add5 = addNumberFactory(5);
// add5にはnumに5が設定されている状態の関数が格納される
function addNumberFactory(5) {
function addNumber(value) {
return 5 + value;
}
return addNumber;
}
const result = add5(10);
// add5(addNumberFactory(5))にはvalueの引数が取れるので、10を渡す。
const result = add5(10);
// return 5 + 10; で15となる。
const add10 = addNumberFactory(10);
const result = add10(10);
// 結果は20となる。
関数を作成する関数に渡す値によって、生成される関数が変わってくるので、動的な関数と呼ぶ。
コメント