6.1 クロージャの概念
クロージャはJavaScriptで最も強力かつ重要な概念の一つだよ。これを使うと、関数が実行された後でもその レキシカルスコープを記憶できるんだ。この講義では、クロージャの概念、特徴、そしてさまざまな使用例を見ていこう。
JavaScriptのクロージャとは、関数とその関数が宣言されたレキシカルスコープの組み合わせのことだよ。 クロージャを使うと、関数は外側のスコープの変数や他の関数にアクセスできるんだ。
クロージャの主な特徴:
- レキシカルスコープ: 関数が宣言された時のコンテキストで、その時点でアクセス可能なすべての変数を含む。
- コンテキストの保存: クロージャ付きの関数は、外側の関数が終了した後でも、外側のスコープの変数にアクセスできる。
6.2 クロージャの例
例 1: シンプルなクロージャ
この例では、innerFunction()がouterVariableを外側のスコープから取得できるんだ。 outerFunction()が終了した後もね。
function outerFunction() {
let outerVariable = 'I am from the outer function';
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
const closure = outerFunction();
closure(); // 結果: I am from the outer function
例 2: クロージャを使ったカウンター
この例では、カウンター関数がcountの値を保持して、呼び出されるたびにそれを増加させるんだ。
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 結果: 1
console.log(counter()); // 結果: 2
console.log(counter()); // 結果: 3
例 3: ループ内のクロージャ
クロージャは、ループ内の変数の値を保存するためによく使われるよ。
この例では、配列arrの中の各関数が、それぞれの作成時点での変数iの値を letのブロックスコープのおかげで記憶しているんだ:
function createArrayWithClosures() {
let arr = [];
for (let i = 0; i < 3; i++) {
arr[i] = function() {
console.log(i);
};
}
return arr;
}
const closures = createArrayWithClosures();
closures[0](); // 結果: 0
closures[1](); // 結果: 1
closures[2](); // 結果: 2
6.3 クロージャの高度な使用シナリオ
例 1: 部分適用 (partial application)
クロージャを使うと、一部の引数を固定した部分適用関数が作れるんだ。
この例では、multiply()関数が引数aを固定して、そのbを掛け算する関数を返すんだ。
function multiply(a) {
return function(b) {
return a * b;
};
}
const double = multiply(2);
console.log(double(5)); // 結果: 10
console.log(double(10)); // 結果: 20
例 2: データの隠蔽 (data hiding)
クロージャは、プライベートな変数とメソッドを作るために使われることもあるよ。
この例では、_nameと_ageの変数はプライベートで、オブジェクトのメソッドを通じてのみアクセスできるんだ:
function createPerson(name, age) {
let _name = name;
let _age = age;
return {
getName: function() {
return _name;
},
getAge: function() {
return _age;
},
setName: function(newName) {
_name = newName;
},
setAge: function(newAge) {
_age = newAge;
}
};
}
const person = createPerson('John', 30);
console.log(person.getName()); // 結果: John
person.setName('Jane');
console.log(person.getName()); // 結果: Jane
console.log(person.getAge()); // 結果: 30
例 3: メモ化 (memoization)
メモ化は、同じ入力値での計算を避けるために、関数の結果を保存する最適化技術だよ。
この例では、memoize()関数が、関数fn()の計算結果をキャッシュするためにクロージャを使用しているんだ:
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (cache[key]) {
return cache[key];
}
const result = fn(...args);
cache[key] = result;
return result;
};
}
function slowFunction(num) {
console.log('Computing...');
return num * 2;
}
const memoizedFunction = memoize(slowFunction);
console.log(memoizedFunction(5)); // 結果: Computing... 10
console.log(memoizedFunction(5)); // 結果: 10 (キャッシュから取得した結果)
GO TO FULL VERSION