関数のネスト
関数の中に、さらに関数を書くことができます。これを 「ネスト(入れ子)」 と呼びます。これは、プログラムを整理して情報を守る 「カプセル化(情報の保護)」 に役立ちます。
親子関係とスコープ
- ルール: 内側の関数(子供)は、外側の関数(親)にある変数を見ることができます。
- 例え: 「子供は自分の家の冷蔵庫(親の変数)を開けて中身を見ることができます。でも、外にいる隣の人(外の関数)は、その家の中を見ることはできません。」
function outerFunc() {
var a;
function innerFunc() {
var b;
}
}
このように構造を作ることで、大切なデータを外から勝手に触られないように守ることができます。
I. 関数のネスト(入れ子構造)
プログラミングをしていると、関数の中にさらに別の関数を書くことがあります。これを 「ネスト(入れ子:いれこ)」 と言います。
これに伴う「スコープ(見える範囲)」のルールは、留学生のみなさんには 「家と部屋」 に例えて説明すると、とても分かりやすくなりますよ!
1. ネスト(入れ子)ってなに?
マトリョーシカ(ロシアの人形)のように、大きな箱の中に小さな箱が入っている状態のことです。
JavaScriptでは、このように書きます。
function outer() { // 外側(そとがわ)の関数(かんすう)(大きな箱)
function inner() { // 内側(うちがわ)の関数(かんすう)(小さな箱)
// 何かの処理
}
}
2. スコープの絶対ルール(家と部屋のルール)
ネストされた関数のスコープには、大切な 2つのルール があります。
ルール①:中は「外」が見える
自分の部屋(内側の関数)にいても、窓から外(外側の関数)の景色は見えますよね。つまり、内側の関数から、外側の変数は使えます。
ルール②:外は「中」が見えない
家の外(外側の関数)にいる人は、あなたの部屋(内側の関数)の引き出しの中身は見えません。つまり、外側の関数から、内側の変数は使えません。
3. 具体的なコードで見てみよう!
このルールを実際のコードで確認してみましょう。
function grandParent() {
let money = "1000円"; // おじいさんのお金
function child() {
let candy = "アメ玉"; // 子供のお菓子
// ✅ ルール①:中は外が見える
console.log(money); // 「1000円」が使える!
}
child();
// ❌ ルール②:外は中が見えない
console.log(candy); // エラー!子供の「アメ玉」は外からは見えません。
}
grandParent();
4. なぜ「ネスト」を使うの?
「わざわざ関数の中に関数を書かなくてもいいのでは?」と思うかもしれません。でも、これには大きなメリットがあります。
- 秘密(ひみつ)を守る:
inner関数は、outer関数の中だけで使う「専用の道具」になります。他の場所から勝手に使われないように隠すことができるのです。 - 整理整頓(せいりせいとん): 関連する機能をまとめておくことで、コードが読みやすくなります。
留学生へのまとめ
| 視点(目線) | 見える? | 理由(たとえ) |
|---|---|---|
| 内側から → 外側へ | 見える! (OK) | 部屋の窓から外が見えるから。 |
| 外側から → 内側へ | 見えない! (NG) | 外から他人の部屋の中は見えないから。 |
Tip
「スコープチェーン」という言葉 もし学校で「スコープチェーン」という言葉が出てきたら、それは**「自分に無ければ、外の箱に探しに行く」**というルールのことだと思ってください。
- 自分の部屋にある?(なければ次へ)
- リビング(外の関数)にある?(なければ次へ)
- お庭(グローバル)にある?
こうやって順番に探しに行くのが、ネストの面白い仕組みです!
いかがでしょうか?「外からは見えないけれど、中からは見える」というルールが分かれば、ネストはもう怖くありません。
II. クロージャ
クロージャ (Closure) は、日本語でいうと 「記憶(きおく)を持っている関数」 のことです。
少し難しい概念ですが、「魔法のリュックサック」 をイメージすると、とても分かりやすくなります。
1. クロージャをイメージで理解しよう!
普通の関数は、仕事が終わると、その中で使っていた変数のことをすべて忘れてしまいます。 しかし、クロージャは違います。
- 普通の関数: 仕事が終わったら、机の上をきれいに片付ける(変数が消える)。
- クロージャ: 仕事が終わっても、大切な変数を**「リュックサック(スコープ)」**に入れて持ち歩く。次に呼ばれたとき、そのリュックの中から前回の続きを取り出せる。
2. 具体的なコードで見てみよう
一番わかりやすい例は、数字を数える「カウンター」です。
function createCounter() {
let count = 0; // これが「リュックの中身(秘密の変数(へんすう))」
return function() {
count++; // 外側(そとがわ)の変数(へんすう)を覚えている!
console.log(count + "回目です");
};
}
const myCounter = createCounter(); // ここで関数(かんすう)(マシン)を受け取る
myCounter(); // 「1回目です」
myCounter(); // 「2回目です」
myCounter(); // 「3回目です」
ここが「魔法」のポイント:
普通、createCounter という関数が動いた後、その中の count = 0 という変数は消えてしまうはずです。
でも、戻ってきた「内側の関数」が count をリュックに入れて持ち続けているので、ずっと数字が増えていくのです。
3. なぜクロージャを使うの?
留学生のみなさんには、この2つのメリットを伝えてあげてください。
- データを隠せる(プライバシー):
countという変数は関数の外からは絶対に見えません。外から勝手に数字を変えられたくない「大切なデータ」を守るのに便利です。 - 専用のマシンが作れる:
const counterA = createCounter();const counterB = createCounter();と書けば、それぞれが 別々のリュック(記憶) を持つことができます。AとBの数字は混ざりません。
4. 留学生向けの言葉のガイド
| 難しい言葉 | やさしい言いかえ | 英語 |
|---|---|---|
| 保持する | ずっと持っている | Hold / Keep |
| カプセル化 | 中身を隠して守る | Encapsulation |
| 参照する | 見に行く / 使う | Reference |
Tip
「閉じる」という意味 クロージャの「クローズ(Close)」は、「変数を関数の中に閉じ込める(閉じ込めて守る)」 という意味から来ています。 「自分だけの秘密のポケットを持っている関数なんだな」と思えばバッチリです!
いかがでしょうか?「関数が変数をリュックに入れて持ち歩いている」というイメージが伝われば、クロージャの理解はぐっと深まります。