my.code(); Logomy.code();
JavaScript-3.関数とクロージャ

my.code(); Logomy.code();

  • C++
    • 0.C++の世界へようこそ
    • 1.型システムと制御構造
    • 2.データ集合とモダンな操作
    • 3.ポインタとメモリ管理
    • 4.関数と参照渡し
    • 5.プロジェクトの分割とビルド
    • 6.クラスの基礎
    • 7.クラスを使いこなす
    • 8.継承とポリモーフィズム
    • 9.テンプレート
    • 10.STL ①:コンテナ
    • 11.STL ②:アルゴリズムとラムダ式
    • 12.RAIIとスマートポインタ
  • JavaScript
    • 0.JavaScriptへようこそ
    • 1.基本構文とデータ型
    • 2.制御構文
    • 3.関数とクロージャ
    • 4.'this'の正体
    • 5.オブジェクトとプロトタイプ
    • 6.クラス構文
    • 7.配列とイテレーション
    • 8.非同期処理①: Promise
    • 9.非同期処理②: Async/Await
  • Python
    • 0.環境構築と基本思想
    • 1.基本構文とデータ型
    • 2.リスト、タプル、辞書、セット
    • 3.制御構文と関数
    • 4.モジュールとパッケージ
    • 5.オブジェクト指向プログラミング
    • 6.ファイルの入出力とコンテキストマネージャ
    • 7.例外処理
    • 8.ジェネレータとデコレータ
  • Ruby
    • 0.rubyの世界へようこそ
    • 1.基本構文とデータ型
    • 2.制御構造とメソッド定義
    • 3.すべてがオブジェクト
    • 4.コレクション (Array, Hash, Range)
    • 5.ブロックとイテレータ
    • 6.クラスとオブジェクト
    • 7.モジュールとMix-in
    • 8.Proc, Lambda, クロージャ
    • 9.標準ライブラリの活用
    • 10.テスト文化入門
    • 11.メタプログラミング入門
  • Rust
    • 0.Rustの世界へようこそ
    • 1.基本構文と「不変性」
    • 2.関数と制御フロー
    • 3.所有権
    • 4.借用とスライス
    • 5.構造体とメソッド構文
    • 6.列挙型とパターンマッチ
    • 7.モジュールシステムとパッケージ管理
    • 8.コレクションと文字列
    • 9.エラーハンドリング
    • 10.ジェネリクスとトレイト
    • 11.ライフタイム
  • TypeScript
    • 0.TypeScriptへようこそ
    • 1.基本的な型と型推論
    • 2.オブジェクト、インターフェース、型エイリアス
    • 3.関数の型定義
    • 4.型を組み合わせる
    • 5.ジェネリクス
    • 6.クラスとアクセス修飾子
    • 7.非同期処理とユーティリティ型
my.code(); Logomy.code();

環境構築不要、その場で実践。

ut-code / my-code

Copyright © 2026 ut.code();

ut.code(); について
公式ウェブサイト公式 𝕏 アカウント

第3章: 関数とクロージャ

JavaScriptにおいて関数はオブジェクトの一種です。つまり、変数に代入したり、他の関数の引数として渡したり、関数から戻り値として返したりすることができます。この柔軟性が、JavaScriptの設計パターンの核心を担っています。

関数の定義(関数宣言 vs 関数式)

JavaScriptには関数を定義する方法が主に2つあります。「関数宣言」と「関数式」です。これらは似ていますが、巻き上げ(Hoisting) の挙動が異なります。

1. 関数宣言 (Function Declaration)

古くからある定義方法です。スクリプトの実行前に読み込まれるため、定義する前の行から呼び出すことができます。

ファイルを編集:function_declaration.js
console.log(greet("Alice")); // 定義前でも呼び出せる

function greet(name) {
   return `Hello, ${name}!`;
}
node function_declaration.js
ブラウザ上で動作するJavaScriptの実行環境です。
左上の実行ボタンを押して、このページ内のfunction_declaration.jsに書かれている内容を実行します。
Hello, Alice!

2. 関数式 (Function Expression)

変数に関数を代入するスタイルです。変数の代入は実行時に行われるため、定義する前に呼び出すとエラーになります。現代のJavaScript開発では、意図しない巻き上げを防ぐためにこちら(または後述のアロー関数)が好まれる傾向にあります。

ファイルを編集:function_expression.js
// 定義前に呼び出すと... ReferenceError: Cannot access 'sayHi' before initialization
// console.log(sayHi("Bob"));

const sayHi = function(name) {
  return `Hi, ${name}!`;
};

console.log(sayHi("Bob"));
node function_expression.js
ブラウザ上で動作するJavaScriptの実行環境です。
左上の実行ボタンを押して、このページ内のfunction_expression.jsに書かれている内容を実行します。
Hi, Bob!

アロー関数 (=>) の構文と特徴

ES2015 (ES6) で導入されたアロー関数は、関数式をより短く記述するための構文です。 function キーワードを省略し、=> (矢印) を使って定義します。 Javaのラムダ式やPythonのlambdaに似ていますが、いくつか独自の特徴があります。

ファイルを編集:arrow_function.js
// 従来の関数式
const add = function(a, b) {
  return a + b;
};

// アロー関数
const addArrow = (a, b) => {
  return a + b;
};

console.log(addArrow(3, 5));
node arrow_function.js
ブラウザ上で動作するJavaScriptの実行環境です。
左上の実行ボタンを押して、このページ内のarrow_function.jsに書かれている内容を実行します。
8

省略記法

アロー関数には強力な省略記法があります。

  1. 引数が1つの場合: カッコ () を省略可能。
  2. 処理が1行でreturnする場合: 中括弧 {} と return キーワードを省略可能(暗黙のreturn)。
JavaScript 実行環境
ブラウザ上で動作するJavaScriptのREPL実行環境です。
プロンプト (>) の後にコマンドを入力し、Enterキーで実行します。
Ctrl+Cまたは左上の停止ボタンで実行中のコマンドを中断できます。
> const square = x => x * x; // 引数の()とreturnを省略
> square(5);
25

> const getUser = (id, name) => ({ id: id, name: name }); // オブジェクトを返す場合は()で囲む
> getUser(1, "Gemini");
{ id: 1, name: 'Gemini' }

注意: アロー関数は単なる短縮記法ではありません。「this を持たない」という重要な特徴がありますが、これについては第5章で詳しく解説します。

引数:デフォルト引数、Restパラメータ (...)

関数の柔軟性を高めるための引数の機能を見ていきましょう。

デフォルト引数

引数が渡されなかった場合(または undefined の場合)に使用される初期値を設定できます。

ファイルを編集:default_args.js
const connect = (host = 'localhost', port = 8080) => {
  console.log(`Connecting to ${host}:${port}...`);
};

connect();                // 両方省略
connect('127.0.0.1');     // portはデフォルト値
connect('example.com', 22); // 両方指定
node default_args.js
ブラウザ上で動作するJavaScriptの実行環境です。
左上の実行ボタンを押して、このページ内のdefault_args.jsに書かれている内容を実行します。
Connecting to localhost:8080...
Connecting to 127.0.0.1:8080...
Connecting to example.com:22...

Restパラメータ (残余引数)

引数の数が不定の場合、... を使うことで、残りの引数を配列として受け取ることができます。以前は arguments オブジェクトを使っていましたが、Restパラメータの方が配列メソッド(map, reduceなど)を直接使えるため便利です。

ファイルを編集:rest_params.js
const sum = (...numbers) => {
  // numbersは本物の配列 [1, 2, 3, 4, 5]
  return numbers.reduce((acc, curr) => acc + curr, 0);
};

console.log(sum(1, 2, 3));
console.log(sum(10, 20, 30, 40, 50));
node rest_params.js
ブラウザ上で動作するJavaScriptの実行環境です。
左上の実行ボタンを押して、このページ内のrest_params.jsに書かれている内容を実行します。
6
150

スコープチェーンとレキシカルスコープ

JavaScriptの変数の有効範囲(スコープ)を理解するために、「レキシカルスコープ」という概念を知る必要があります。

  • レキシカルスコープ (Lexical Scope): 関数が「どこで呼び出されたか」ではなく、「どこで定義されたか」によってスコープが決まるというルールです。
  • スコープチェーン (Scope Chain): 変数を探す際、現在のスコープになければ、定義時の外側のスコープへと順番に探しに行く仕組みです。
ファイルを編集:scope.js
const globalVar = "Global";

function outer() {
 const outerVar = "Outer";
 function inner() {
   const innerVar = "Inner";
   // innerの中からouterVarとglobalVarが見える(スコープチェーン)
   return `${globalVar} > ${outerVar} > ${innerVar}`;
 }
 return inner();
}

console.log(outer());
node scope.js
ブラウザ上で動作するJavaScriptの実行環境です。
左上の実行ボタンを押して、このページ内のscope.jsに書かれている内容を実行します。
Global > Outer > Inner

クロージャ:関数が状態を持つ仕組み

クロージャ (Closure) は、この章の最重要トピックです。 一言で言えば、「外側の関数のスコープにある変数を、外側の関数の実行終了後も参照し続ける関数」のことです。

なぜクロージャを使うのか?

  1. カプセル化 (Encapsulation): 変数を隠蔽し、特定の関数経由でしか変更できないようにすることで、予期せぬバグを防ぎます。
  2. 状態の保持: グローバル変数を使わずに、関数単位で永続的な状態を持てます。
  3. 関数ファクトリ: 設定の異なる関数を動的に生成する場合に役立ちます。

プライベートな変数を持つカウンタを作ってみましょう。

通常、関数(createCounter)の実行が終わると、そのローカル変数(count)はメモリから破棄されます。しかし、その変数を参照している内部関数(increment)が存在し、その内部関数が外部に返された場合、変数は破棄されずに保持され続けます。

ファイルを編集:closure_counter.js
const createCounter = () => {
  let count = 0; // この変数は外部から直接アクセスできない(プライベート変数的な役割)

  return () => {
    count++;
    console.log(`Current count: ${count}`);
  };
};

const counterA = createCounter(); // counterA専用のスコープ(環境)が作られる
const counterB = createCounter(); // counterB専用のスコープが別に作られる

counterA(); // 1
counterA(); // 2
counterA(); // 3

console.log("--- switching to B ---");

counterB(); // 1 (Aの状態とは独立している)
node closure_counter.js
ブラウザ上で動作するJavaScriptの実行環境です。
左上の実行ボタンを押して、このページ内のclosure_counter.jsに書かれている内容を実行します。
Current count: 1
Current count: 2
Current count: 3
--- switching to B ---
Current count: 1

この章のまとめ

  • 関数定義: 巻き上げが起こる「関数宣言」と、起こらない「関数式(アロー関数含む)」がある。
  • アロー関数: (args) => body の形式で記述し、this の挙動が従来と異なる。
  • 引数: デフォルト引数とRestパラメータ(...args)で柔軟な引数処理が可能。
  • レキシカルスコープ: 関数は「定義された場所」のスコープを記憶する。
  • クロージャ: 内部関数が外部関数の変数を参照し続ける仕組み。データの隠蔽や状態保持に使われる。

練習問題1: アロー関数への書き換え

以下の関数宣言を、アロー関数 isEven に書き換えてください。ただし、省略可能な記号(カッコやreturnなど)は可能な限り省略して最短で記述してください。

ファイルを編集:practice4_1.js
function isEven(n) {
  return n % 2 === 0;
}
node practice4_1.js
ブラウザ上で動作するJavaScriptの実行環境です。
左上の実行ボタンを押して、このページ内のpractice4_1.jsに書かれている内容を実行します。

問題2: クロージャによる掛け算生成器

createMultiplier という関数を作成してください。この関数は数値 x を引数に取り、呼び出すたびに「引数を x 倍して返す関数」を返します。

使用例:

ファイルを編集:practice4_2.js
// ここに関数を作成


const double = createMultiplier(2);
console.log(double(5)); // 10

const triple = createMultiplier(3);
console.log(triple(5)); // 15
node practice4_2.js
ブラウザ上で動作するJavaScriptの実行環境です。
左上の実行ボタンを押して、このページ内のpractice4_2.jsに書かれている内容を実行します。
前のページ« 制御構文
次のページ'this'の正体 »