🌊

【基礎から学ぶ】関数の作り方と使い方を徹底解説

2025/03/11に公開
2

プログラミングにおいて、関数は最も重要な基本要素の1つです。コードの再利用性を高め、プログラムを整理するために不可欠な存在です。この記事では、関数の基本的な概念から実践的な使い方まで、初心者にもわかりやすく解説します。

関数とは?

関数は、特定の処理をまとめた「部品」のようなものです。一度作った関数は、必要なときに何度でも使うことができます。

関数を使うメリット

  1. コードの再利用

    • 同じ処理を何度も書く必要がない
    • 変更が必要な場合も1箇所を修正するだけでよい
  2. プログラムの整理

    • 処理をわかりやすい単位に分割できる
    • コードの見通しが良くなる
  3. 保守性の向上

    • バグの修正が容易になる
    • 機能の追加や変更がしやすくなる

関数の基本構造

JavaScriptを例に、関数の基本的な構造を見ていきましょう。

関数の宣言

// 基本的な関数の形
function greet(name) {
  return "こんにちは、" + name + "さん!";
}

// 関数の使用
let message = greet("田中");
console.log(message);  // "こんにちは、田中さん!"

関数の構成要素:

  • function: 関数を定義するキーワード
  • greet: 関数名
  • (name): パラメータ(引数)
  • return: 戻り値を指定するキーワード

関数の種類

JavaScriptには、関数を定義する複数の方法があります。

1. 関数宣言

// 関数宣言
function add(a, b) {
  return a + b;
}

console.log(add(5, 3));  // 8

2. 関数式

// 関数式
const multiply = function(a, b) {
  return a * b;
};

console.log(multiply(4, 2));  // 8

3. アロー関数式

// アロー関数式(ES6以降)
const divide = (a, b) => {
  return a / b;
};

// 1行で書ける場合は更にシンプルに
const subtract = (a, b) => a - b;

console.log(divide(10, 2));    // 5
console.log(subtract(10, 3));  // 7

パラメータと戻り値

パラメータの使い方

// 基本的なパラメータ
function greet(firstName, lastName) {
  return `こんにちは、${lastName}${firstName}さん!`;
}

// デフォルト値の設定
function greetWithTitle(name, title = "さん") {
  return `こんにちは、${name}${title}`;
}

// 可変長引数
function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}

console.log(greet("太郎", "山田"));        // "こんにちは、山田太郎さん!"
console.log(greetWithTitle("田中"));       // "こんにちは、田中さん!"
console.log(greetWithTitle("山本", "先生")); // "こんにちは、山本先生!"
console.log(sum(1, 2, 3, 4, 5));          // 15

戻り値の使い方

// 単一の値を返す
function square(n) {
  return n * n;
}

// 複数の値を返す(オブジェクトとして)
function getPersonInfo(name, age) {
  return {
    name: name,
    age: age,
    isAdult: age >= 20
  };
}

// 配列を返す
function splitName(fullName) {
  return fullName.split(" ");
}

console.log(square(5));                    // 25
console.log(getPersonInfo("山田太郎", 25));  // { name: "山田太郎", age: 25, isAdult: true }
console.log(splitName("山田 太郎"));        // ["山田", "太郎"]

スコープと変数の有効範囲

関数内で宣言された変数は、その関数の外からアクセスできません。

function calculateTotal() {
  let subtotal = 1000;  // この変数は関数の中でのみ有効
  let tax = subtotal * 0.1;
  return subtotal + tax;
}

console.log(calculateTotal());  // 1100
// console.log(subtotal);      // エラー:subtotalは定義されていない

グローバル変数とローカル変数

let globalVar = "グローバル変数";  // グローバルスコープ

function showScope() {
  let localVar = "ローカル変数";   // 関数スコープ
  console.log(globalVar);        // グローバル変数にアクセス可能
  console.log(localVar);         // ローカル変数にアクセス可能
}

showScope();
console.log(globalVar);          // グローバル変数にアクセス可能
// console.log(localVar);        // エラー:ローカル変数にはアクセス不可

実践的な関数の例

1. 配列の操作

// 配列の要素を2倍にする関数
function doubleArray(arr) {
  return arr.map(num => num * 2);
}

// 配列の合計を計算する関数
function calculateSum(arr) {
  return arr.reduce((sum, num) => sum + num, 0);
}

// 特定の条件で配列をフィルタリングする関数
function filterEvenNumbers(arr) {
  return arr.filter(num => num % 2 === 0);
}

const numbers = [1, 2, 3, 4, 5];
console.log(doubleArray(numbers));       // [2, 4, 6, 8, 10]
console.log(calculateSum(numbers));      // 15
console.log(filterEvenNumbers(numbers)); // [2, 4]

2. オブジェクトの操作

// ユーザーオブジェクトを作成する関数
function createUser(name, age, email) {
  return {
    name,
    age,
    email,
    createdAt: new Date(),
    isAdult: age >= 20
  };
}

// ユーザー情報をフォーマットする関数
function formatUserInfo(user) {
  return `${user.name}${user.age}歳)- ${user.email}`;
}

const user = createUser("山田太郎", 25, "yamada@example.com");
console.log(user);
console.log(formatUserInfo(user));

3. 非同期処理

// Promise を使用した非同期関数
async function fetchUserData(userId) {
  try {
    const response = await fetch(`https://api.example.com/users/${userId}`);
    const data = await response.json();
    return data;
  } catch (error) {
    console.error("エラーが発生しました:", error);
    return null;
  }
}

// タイマー関数
function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// 使用例
async function main() {
  console.log("処理開始");
  await delay(1000);
  console.log("1秒経過");
  await delay(1000);
  console.log("2秒経過");
}

関数の設計のベストプラクティス

1. 単一責任の原則

関数は1つのことだけを行うようにしましょう。

// 悪い例:複数の責任を持つ関数
function processUserData(user) {
  validateUser(user);
  saveToDatabase(user);
  sendEmail(user);
}

// 良い例:責任を分割した関数
function validateUser(user) {
  // ユーザーデータの検証のみを行う
}

function saveUser(user) {
  // データベースへの保存のみを行う
}

function notifyUser(user) {
  // メール送信のみを行う
}

2. 適切な命名

関数名は、その機能を明確に表すものにしましょう。

// 悪い例
function process(data) {
  // 何を処理するのかわからない
}

// 良い例
function calculateTotalPrice(items) {
  return items.reduce((total, item) => total + item.price, 0);
}

3. エラーハンドリング

関数は適切にエラーを処理する必要があります。

function divideNumbers(a, b) {
  // パラメータの検証
  if (typeof a !== 'number' || typeof b !== 'number') {
    throw new Error('引数は数値である必要があります');
  }

  // ゼロ除算の防止
  if (b === 0) {
    throw new Error('0で除算することはできません');
  }

  return a / b;
}

// 使用例
try {
  console.log(divideNumbers(10, 2));  // 5
  console.log(divideNumbers(10, 0));  // エラーが発生
} catch (error) {
  console.error('エラーが発生しました:', error.message);
}

デバッグとテスト

コンソールログを使ったデバッグ

function calculateDiscount(price, quantity) {
  console.log('入力値:', { price, quantity });

  let discount = 0;
  if (quantity >= 10) {
    discount = 0.1;
  } else if (quantity >= 5) {
    discount = 0.05;
  }
  console.log('適用される割引率:', discount);

  const total = price * quantity * (1 - discount);
  console.log('計算結果:', total);

  return total;
}

単体テストの例

// テスト関数
function testCalculateDiscount() {
  // テストケース1: 通常価格
  console.assert(
    calculateDiscount(100, 1) === 100,
    '単品購入のテストが失敗しました'
  );

  // テストケース2: 5個以上で5%割引
  console.assert(
    calculateDiscount(100, 5) === 475,
    '5個購入の割引テストが失敗しました'
  );

  // テストケース3: 10個以上で10%割引
  console.assert(
    calculateDiscount(100, 10) === 900,
    '10個購入の割引テストが失敗しました'
  );

  console.log('すべてのテストが成功しました!');
}

まとめ

関数は、プログラミングの基本的かつ重要な要素です。以下のポイントを押さえておきましょう:

  1. 基本構造を理解する

    • 関数の宣言方法
    • パラメータと戻り値の使い方
    • スコープの概念
  2. 適切な設計を心がける

    • 単一責任の原則
    • 明確な命名
    • エラーハンドリング
  3. 実践的な使い方を学ぶ

    • 配列やオブジェクトの操作
    • 非同期処理
    • デバッグとテスト

関数の基本を理解し、適切に使用することで、より保守性が高く、再利用可能なコードを書くことができます。

次のステップ

関数の基本を理解したら、以下の記事も参考にしてください:

Discussion

宝松@システムエンジニア宝松@システムエンジニア

ご指摘いただき、ありがとうございます!
仰るとおり、「関数式」と「アロー関数(式)」の記述方法が混ざってしまい、少々わかりづらくなっていましたね。

ご提案いただいたように、

  • 関数宣言
  • 関数式
  • アロー関数式

のように、分類と表記方法を明確に整理して修正します。読み手が混乱しないように、記事も修正しておきますね。

丁寧なフィードバックで大変助かりました!
引き続きよろしくお願いいたします。