さとまたプログラミングラボ

関数

処理をまとめて再利用可能にする

関数とは?

日常での例え:自動販売機

入力(引数):お金とボタン選択

処理:飲み物を出す

出力(戻り値):選んだ飲み物

関数は「決まった処理をして結果を返す箱」のようなもの

なぜ関数が必要?

同じ処理を何度も書くと:

  • コードが長くなって読みにくい
  • 修正が必要な時、全箇所を直す必要がある
  • バグが入りやすい

関数にまとめると:1箇所に書いて、何度でも呼び出せる!修正も1箇所だけでOK

関数の宣言

関数宣言

functionキーワードで定義

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

// 呼び出し
const message = greet("田中");
console.log(message); // "こんにちは、田中さん!"
プレビュー
greet("田中")
// → "こんにちは、田中さん!"

関数式

変数に代入する形式

javascript
// 関数式
const add = function(a, b) {
  return a + b;
};

// 即座に実行
console.log(add(5, 3)); // 8
プレビュー
add(5, 3)
// → 8

アロー関数

モダンで簡潔な書き方

javascript
// 基本形
const multiply = (a, b) => {
  return a * b;
};

// 1行なら return 省略可
const multiply2 = (a, b) => a * b;

// 引数1つなら () 省略可
const double = n => n * 2;

// 引数なし
const sayHello = () => "Hello!";
プレビュー
multiply(4, 5) // → 20
double(7) // → 14
sayHello() // → "Hello!"

引数と戻り値

デフォルト引数

引数が省略された時の初期値

javascript
function greet(name = "ゲスト") {
  return "こんにちは、" + name + "さん!";
}

greet();        // "こんにちは、ゲストさん!"
greet("田中");  // "こんにちは、田中さん!"
プレビュー
greet() // → "こんにちは、ゲストさん!"
greet("田中") // → "こんにちは、田中さん!"

残余引数(Rest Parameters)

可変長の引数を配列で受け取る

javascript
function sum(...numbers) {
  return numbers.reduce((total, n) => total + n, 0);
}

sum(1, 2);           // 3
sum(1, 2, 3, 4, 5);  // 15
プレビュー
sum(1, 2) // → 3
sum(1, 2, 3, 4, 5) // → 15

分割代入(オブジェクト引数)

オブジェクトのプロパティを展開

javascript
// 引数をオブジェクトで受け取る
function createUser({ name, age, email }) {
  return { name, age, email, createdAt: new Date() };
}

// 呼び出し
createUser({
  name: "田中",
  age: 25,
  email: "tanaka@example.com"
});
プレビュー
// オブジェクトで引数を渡すと
// 順番を気にしなくて良い

コールバック関数

コールバック関数とは?

「後で呼び出してもらう関数」のこと。
ある処理が終わった後に「これを実行して」と渡しておく関数です。

:配列の各要素に対して「この処理をして」と関数を渡す

関数を引数として渡す

他の関数に処理を委ねる

javascript
// 関数を引数に取る関数
function processArray(arr, callback) {
  const result = [];
  for (const item of arr) {
    result.push(callback(item));
  }
  return result;
}

// 使用例
const numbers = [1, 2, 3, 4, 5];
const doubled = processArray(numbers, n => n * 2);
// [2, 4, 6, 8, 10]
プレビュー
numbers = [1, 2, 3, 4, 5]
callback = n => n * 2
// → [2, 4, 6, 8, 10]

配列メソッドでのコールバック

map, filter, reduce など

javascript
const numbers = [1, 2, 3, 4, 5];

// map: 各要素を変換
numbers.map(n => n * 2);     // [2, 4, 6, 8, 10]

// filter: 条件に合う要素を抽出
numbers.filter(n => n > 2);  // [3, 4, 5]

// find: 条件に合う最初の要素
numbers.find(n => n > 3);    // 4

// reduce: 1つの値に集約
numbers.reduce((sum, n) => sum + n, 0); // 15
プレビュー
.map(n => n * 2) // [2, 4, 6, 8, 10]
.filter(n => n > 2) // [3, 4, 5]
.find(n => n > 3) // 4
.reduce((sum, n) => sum + n, 0) // 15

スコープとクロージャ

「スコープ」とは?

変数が「見える範囲」のこと。
関数の中で作った変数は、その関数の中でしか使えない(他から見えない)。

「クロージャ」とは?

関数が「外側の変数を覚えている」仕組み。
これを使うと、関数の中だけで使える「プライベートな変数」が作れる。

スコープ

変数の有効範囲

javascript
const globalVar = "グローバル";

function outer() {
  const outerVar = "outer";

  function inner() {
    const innerVar = "inner";
    console.log(globalVar); // OK
    console.log(outerVar);  // OK
    console.log(innerVar);  // OK
  }

  console.log(innerVar);  // エラー!
}
プレビュー
// 内側から外側は参照OK
// 外側から内側は参照NG

クロージャ

外部スコープの変数を記憶

javascript
function createCounter() {
  let count = 0;  // プライベート変数

  return {
    increment() { count++; },
    decrement() { count--; },
    getCount() { return count; }
  };
}

const counter = createCounter();
counter.increment();
counter.increment();
counter.getCount(); // 2
プレビュー
counter.increment()
counter.increment()
counter.getCount() // → 2