関数の定義
関数宣言
function greet(name) {
return `こんにちは、${name}さん!`;
}
console.log(greet("太郎")); // こんにちは、太郎さん!
// 巻き上げ(hoisting)により、宣言前に呼び出し可能
sayHello(); // OK
function sayHello() {
console.log("Hello!");
}
関数式
const greet = function(name) {
return `こんにちは、${name}さん!`;
};
// 巻き上げされない
// sayHi(); // エラー
const sayHi = function() {
console.log("Hi!");
};
アロー関数(ES6)
// 基本形
const greet = (name) => {
return `こんにちは、${name}さん!`;
};
// 引数が1つなら括弧を省略可能
const greet = name => {
return `こんにちは、${name}さん!`;
};
// 1行なら{}とreturnを省略可能
const greet = name => `こんにちは、${name}さん!`;
// 引数がないとき
const sayHello = () => "Hello!";
// オブジェクトを返すとき(括弧が必要)
const createUser = name => ({ name, createdAt: new Date() });
引数
デフォルト引数
function greet(name = "ゲスト") {
return `こんにちは、${name}さん!`;
}
console.log(greet()); // こんにちは、ゲストさん!
console.log(greet("太郎")); // こんにちは、太郎さん!
残余引数(Rest Parameters)
function sum(...numbers) {
return numbers.reduce((acc, n) => acc + n, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15
// 他の引数と組み合わせ
function log(level, ...messages) {
console.log(`[${level}]`, ...messages);
}
log("INFO", "ユーザー", "ログイン");
分割代入(引数)
function printUser({ name, age }) {
console.log(`${name}(${age}歳)`);
}
const user = { name: "太郎", age: 25 };
printUser(user); // 太郎(25歳)
// デフォルト値付き
function createUser({ name, role = "user" } = {}) {
return { name, role };
}
コールバック関数
function doSomething(callback) {
console.log("処理を実行中...");
callback();
}
doSomething(() => {
console.log("コールバック実行!");
});
// 配列メソッドでよく使う
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
クロージャ
function createCounter() {
let count = 0; // この変数は外部からアクセス不可
return {
increment() {
count++;
return count;
},
decrement() {
count--;
return count;
},
getCount() {
return count;
}
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
console.log(counter.getCount()); // 1
// console.log(count); // エラー(アクセス不可)
クロージャの活用例
// 関数を生成する関数
function multiplyBy(factor) {
return (number) => number * factor;
}
const double = multiplyBy(2);
const triple = multiplyBy(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
// プライベート変数
function createBankAccount(initialBalance) {
let balance = initialBalance;
return {
deposit(amount) {
balance += amount;
return balance;
},
withdraw(amount) {
if (amount > balance) {
throw new Error("残高不足");
}
balance -= amount;
return balance;
},
getBalance() {
return balance;
}
};
}
高階関数
// 関数を返す関数
function createGreeter(greeting) {
return function(name) {
return `${greeting}, ${name}!`;
};
}
const sayHello = createGreeter("Hello");
const sayHi = createGreeter("Hi");
console.log(sayHello("太郎")); // Hello, 太郎!
console.log(sayHi("花子")); // Hi, 花子!
// 関数を受け取る関数
function repeat(n, action) {
for (let i = 0; i < n; i++) {
action(i);
}
}
repeat(3, i => console.log(`${i}回目`));
thisの挙動
const user = {
name: "太郎",
greet() {
console.log(`こんにちは、${this.name}です`);
},
greetArrow: () => {
console.log(`こんにちは、${this.name}です`); // thisが違う
}
};
user.greet(); // こんにちは、太郎です
user.greetArrow(); // こんにちは、undefinedです
// コールバックでのthis問題
const user2 = {
name: "花子",
friends: ["太郎", "次郎"],
showFriends() {
// アロー関数はthisを継承する
this.friends.forEach(friend => {
console.log(`${this.name}の友達: ${friend}`);
});
}
};
user2.showFriends();
// 花子の友達: 太郎
// 花子の友達: 次郎
即時実行関数(IIFE)
// グローバルスコープを汚染しない
(function() {
const privateVar = "秘密";
console.log(privateVar);
})();
// console.log(privateVar); // エラー
// アロー関数版
(() => {
console.log("即時実行");
})();
まとめ
- 関数宣言は巻き上げされる、関数式はされない
- アロー関数は簡潔で
thisを継承する ...argsで可変長引数を受け取れる- クロージャで変数をカプセル化できる
- コールバックと高階関数はJavaScriptの基本
次回は配列とオブジェクトについて学びます。