
JavaScriptの関数:定義と呼び出し
2025-07-28はじめに
JavaScriptの関数は、一連の処理をまとめて名前を付けた「再利用できる命令のかたまり」です。引数を受け取って処理し、結果を返すことができます。コードの重複を減らし、プログラムを整理するために使います。
関数の基本概念
関数はJavaScriptにおける重要な構成要素で、特定のタスクを実行するコードブロックです。関数を使うことで、コードの再利用性、可読性、保守性が向上します。
関数の利点
- コードの再利用: 同じ処理を何度も書かなくて済む
- モジュール化: プログラムを小さな機能単位に分割できる
- 保守性向上: 変更が必要な場合、1箇所を修正するだけで済む
関数の定義方法
関数を使うためには、まず関数を定義(作成)し、その後呼び出して実行する手順が必要です。
1. 関数宣言(Function Declaration)
JavaScriptで最も初歩的な関数宣言は、関数宣言(function宣言)と呼ばれる書き方です。
// 関数宣言
function greet(name) {
return `こんにちは、${name}さん!`;
}
// 呼び出し
console.log(greet('太郎')); // こんにちは、太郎さん!
特徴:
- ホイスティングされる(定義前に呼び出せる)
- ブロックスコープではなく関数スコープ
2. 関数式(Function Expression)
関数式は、関数を変数に代入する方法で、関数宣言とは違い「変数名を使って関数を呼び出す」形になります。
// 関数式
const greet = function(name) { // greet変数に関数を代入する
return `こんにちは、${name}さん!`;
};
// 呼び出し
console.log(greet('花子')); // こんにちは、花子さん!
特徴:
- 変数に代入される
- ホイスティングされない
- 無名関数(匿名関数)としても使用可能
3. アロー関数(Arrow Function)ES6
無名関数は「一時的に使いたい処理」や「イベント処理、配列の操作時のコールバック」として便利で、コードを簡潔にできます。
※コールバックについては後ほど説明します。
// アロー関数
const greet = (name) => {
return `こんにちは、${name}さん!`;
};
// 簡潔な構文(単一式の場合)
const square = x => x * x;
特徴:
this
のバインドが異なる(後述)- 簡潔な構文
- コンストラクタとして使用できない
関数の呼び出し
JavaScriptで関数を使うには、定義した関数名の後に丸括弧 () を付けて呼び出します。このとき、必要に応じて丸括弧の中に引数を渡すことができます。
基本的な呼び出し
定義した関数名の後に丸括弧 ()
を付けて呼び出します。
function add(a, b) {
return a + b;
}
const result = add(3, 5); // 8
メソッドとしての呼び出し
変数に格納された関数を呼び出すとは、関数を代入した変数名に続けて括弧 ()
を記述します。
const calculator = {
add: function(a, b) {
return a + b;
}
};
calculator.add(2, 3); // 5
コンストラクタとしての呼び出し
new
演算子と組み合わせて使用され、新しいオブジェクトを生成し、初期化する役割を担います。
function Person(name) {
this.name = name;
}
const person = new Person('太郎');
間接的な呼び出し
関数名の後に直接 () を付けて実行するのではなく、関数を別の変数に代入したり、他の関数の引数として渡したりして、あとから呼び出す方法です。
function greet() {
console.log(`こんにちは、${this.name}さん!`);
}
const user = { name: '花子' };
greet.call(user); // こんにちは、花子さん!
パラメータと引数
パラメータ:関数を定義するときに、処理のために受け取る変数の名前のこと。
引数:関数を呼び出すときに、パラメータに渡す具体的な値のこと。
デフォルトパラメータ(ES6)
デフォルトパラメータは、関数のパラメータに初期値を設定できるES6の機能です。呼び出し時に引数が渡されなかったり、undefinedの場合に、あらかじめ指定した値が使われます。
function greet(name = 'ゲスト') {
console.log(`こんにちは、${name}さん!`);
}
greet(); // こんにちは、ゲストさん!
greet('太郎'); // こんにちは、太郎さん!
残余パラメータ(Rest Parameters)
残余パラメータ(Rest Parameters)は、関数の引数をまとめて配列として受け取るES6の機能です。関数が不特定多数の引数を扱いたいときに便利です。
function sum(...numbers) {
return numbers.reduce((acc, num) => acc + num, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15
引数の分割代入
引数の分割代入とは、関数の引数としてオブジェクトや配列を受け取り、その中の値を直接変数に取り出す書き方です。コードがシンプルで見やすくなります。
function printUser({ name, age }) {
console.log(`${name}さんは${age}歳です`);
}
const user = { name: '太郎', age: 25 };
printUser(user); // 太郎さんは25歳です
戻り値とスコープ
戻り値(return値):関数が処理結果を呼び出し元に返す値のこと
スコープ:変数や関数が「見える(アクセスできる)」範囲のこと
戻り値の重要性
戻り値(return値)は、関数が処理結果を呼び出し元に返す値のことです。returnキーワードで指定し、戻り値があることで関数の結果を他の処理に使えます。
// 戻り値がある関数
function add(a, b) {
return a + b;
}
// 戻り値がない関数(undefinedを返す)
function noReturn() {
// 何も返さない
}
スコープの挙動
スコープは、変数や関数が「見える(アクセスできる)」範囲のことです。関数内で宣言した変数はその関数内だけ有効(ローカルスコープ)で、外からは見えません。グローバルスコープはプログラム全体で有効な範囲です。
let globalVar = 'グローバル';
function testScope() {
let localVar = 'ローカル';
console.log(globalVar); // アクセス可能
console.log(localVar); // アクセス可能
}
testScope();
console.log(globalVar); // アクセス可能
// console.log(localVar); // エラー(アクセス不可)
応用関数
高階関数(Higher-Order Function)
高階関数(Higher-Order Function)とは、関数を引数に取ったり、関数を返したりする関数のことです。処理を柔軟に組み合わせるのに使います。
// 関数を引数に取る関数
function operate(a, b, operation) {
return operation(a, b);
}
function add(x, y) { return x + y; }
function multiply(x, y) { return x * y; }
console.log(operate(3, 4, add)); // 7
console.log(operate(3, 4, multiply)); // 12
コールバック関数
コールバック関数(Callback Function)は、他の関数に渡されて実行される関数のことです。非同期処理やイベント処理でよく使われます。
// コールバックを使用した非同期処理の模倣
function fetchData(callback) {
setTimeout(() => {
callback('データ');
}, 1000);
}
fetchData(data => {
console.log('取得したデータ:', data);
});
コールバックとは、ある関数を呼び出す際に、別の関数を引数として渡し、その引数として渡された関数を、元の関数の中で後で実行させる仕組みのことです。
即時実行関数式(IIFE)
即時実行関数式(IIFE: Immediately Invoked Function Expression)は、関数を定義すると同時にすぐ実行する仕組みです。
- 一度だけ実行される
- 変数のスコープを限定してグローバル汚染を防ぐ
- 古いJavaScriptでもモジュールのように使える
// 定義と同時に実行
(function() {
console.log('即時実行');
})();
// スコープを隔離する用途で使用
(function() {
let privateVar = '外部からアクセス不可';
// ここでの変数は外部から見えない
})();
再帰関数
再帰関数とは、自分自身を呼び出す関数のことです。繰り返し処理や階層的なデータ処理に使われます。ポイントは「終了条件(ベースケース)」を必ず設けて、無限に呼び出され続けないようにすることです。
// 階乗を計算する再帰関数
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120
関数のベストプラクティス
- 単一責任の原則: 1つの関数は1つのことだけを行う
- 説明的な名前: 関数名から機能がわかるように
- 適切な長さ: 一般的に20行以内が目安
- 副作用を最小限に: 外部状態を変更しない純粋関数を目指す
- デフォルト引数を使用: 未定義エラーを防ぐ
- 適切なコメント: 複雑なロジックには説明を追加
まとめ
関数はプログラムの基本単位で、繰り返し使える便利な仕組み。目的ごとに処理を分けて書くことで、読みやすく修正しやすいコードになります。関数を覚えることはJavaScriptの理解に欠かせません。
演習問題
初級問題(3問)
- 次の関数を関数式とアロー関数で書き換えなさい。
function multiply(a, b) {
return a * b;
}
- 次の関数呼び出しの出力結果は?
function sayHello(name = 'ゲスト') {
console.log(`こんにちは、${name}さん!`);
}
sayHello();
sayHello('太郎');
- 次の関数の間違いを指摘し、修正しなさい。
function sum(a, b) {
console.log(a + b);
}
const result = sum(2, 3);
console.log(result);
中級問題(6問)
- 次の関数を残余パラメータを使用して書き換えなさい。
function sum(a, b, c) {
return a + b + c;
}
- 次のコードの出力結果とその理由を説明しなさい。
let x = 10;
function updateX() {
x = 20;
}
updateX();
console.log(x);
- 引数として受け取った数値が 正の数か負の数かを判定する関数 isPositive を作成しなさい。ゼロの場合は "zero"、正の数は "positive"、負の数は "negative" を返すようにしてください。
- 次の高階関数を使用して、配列の各要素を2倍にするコードを書きなさい。
function mapArray(arr, transform) {
const result = [];
for (let item of arr) {
result.push(transform(item));
}
return result;
}
- オブジェクトを受け取り、そのプロパティをすべて表示する関数
printObject
を作成しなさい。 - 次の再帰関数の動作を説明し、
factorial(4)
の呼び出し時の実行フローを追跡しなさい。
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
上級問題(3問)
- カリー化された関数
add
を作成しなさい。以下のように動作するものとします。
console.log(add(2)(3)(4)()); // 9
console.log(add(1)(2)()); // 3
- メモ化を実装したフィボナッチ関数を作成しなさい。再帰計算の効率を向上させること。
- 以下の要件を満たす関数
createCounter
を実装しなさい。
- 呼び出すたびに1ずつ増加するカウンタを返す
- 複数の独立したカウンタを作成可能
- 初期値と増分値を指定可能
const counter1 = createCounter();
console.log(counter1()); // 1
console.log(counter1()); // 2
const counter2 = createCounter(10, 5);
console.log(counter2()); // 15
console.log(counter2()); // 20
解答例
初級問題解答
- 関数式とアロー関数で書き換え
// 関数式
const multiply = function(a, b) {
return a * b;
};
// アロー関数
const multiply = (a, b) => a * b;
- 呼び出しの出力結果
こんにちは、ゲストさん!
こんにちは、太郎さん!
function sayHello(name = 'ゲスト') {
console.log(`こんにちは、${name}さん!`);
}
sayHello(); // こんにちは、ゲストさん!
sayHello('太郎'); // こんにちは、太郎さん!
- 間違いと修正
// 間違い: console.logで出力しているだけで値を返していない
// 修正例:
function sum(a, b) {
return a + b;
}
中級問題解答
- 残余パラメータを使用して書き換え
function sum(...numbers) {
return numbers.reduce((acc, num) => acc + num, 0);
}
- コードの出力結果とその理由
20
let x = 10;
function updateX() {
x = 20; // 宣言してないのでグローバル変数として認識される
}
updateX(); // 関数内でグローバル変数xを更新しているため
console.log(x);
- 正の数か負の数かを判定する関数 isPositive
function isPositive(num) {
if (num > 0) {
return "positive";
} else if (num < 0) {
return "negative";
} else {
return "zero";
}
}
- 高階関数を使用して、配列の各要素を2倍にするコード
const doubled = mapArray([1, 2, 3], x => x * 2);
// [2, 4, 6]
- プロパティをすべて表示する関数
printObject
function printObject(obj) {
for (const key in obj) {
console.log(`${key}: ${obj[key]}`);
}
}
factorial(4)
の実行フロー
factorial(4)
→ 4 * factorial(3)
→ 3 * factorial(2)
→ 2 * factorial(1)
→ 1 (ベースケース)
→ 2 * 1 = 2
→ 3 * 2 = 6
→ 4 * 6 = 24
上級問題解答
- カリー化された関数
add
function add(a) {
return function(b) {
return function(c) {
return function() {
return a + b + c;
};
};
};
}
関数のカリー化とは、一回性で必要な引数を入れるのではなく、あらかじめ関数の引数を数段階に分けて、段階別に引数を自由に操作できる構造です。
- メモ化を実装したフィボナッチ関数
function fibonacci(n, memo = {}) {
if (n in memo) return
memo[n];
if (n <= 1) return n;
memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo);
return memo[n];
}
createCounter
関数:
javascript function createCounter(initial = 0, step = 1) {
let count = initial;
return function() {
count += step;
return count;
};
}