関数
JavaScript
関数宣言、アロー関数、クロージャ
関数の定義方法
宣言、式、アロー関数
// 関数宣言(巻き上げあり)
function greet(name) {
return `こんにちは、${name}!`;
}
// 関数式(巻き上げなし)
const greet = function(name) {
return `こんにちは、${name}!`;
};
// アロー関数
const greet = (name) => `こんにちは、${name}!`;
// アロー関数 — オブジェクト返却
const makeUser = (name, age) => ({ name, age });
// アロー関数 — 複数行
const add = (a, b) => {
const result = a + b;
return result;
};
// デフォルト引数
function connect(host = 'localhost', port = 3000) {
return `${host}:${port}`;
}
// 残余引数(rest parameters)
function sum(...nums) {
return nums.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4); // 10クロージャ
外部スコープの変数を参照し続ける関数
// カウンター
function makeCounter(start = 0) {
let count = start;
return {
increment() { return ++count; },
decrement() { return --count; },
value() { return count; },
};
}
const counter = makeCounter(10);
counter.increment(); // 11
counter.increment(); // 12
counter.value(); // 12
// プライベート変数のエミュレーション
function createUser(name) {
let _password = null; // 外からアクセス不可
return {
getName: () => name,
setPassword: (pw) => { _password = pw; },
verify: (pw) => pw === _password,
};
}
// メモ化
function memoize(fn) {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}高階関数
関数を引数・戻り値として扱う
// 関数を引数に取る
function applyTwice(fn, value) {
return fn(fn(value));
}
applyTwice(x => x * 2, 3); // 12
// 関数を返す
function multiply(factor) {
return (n) => n * factor;
}
const double = multiply(2);
const triple = multiply(3);
double(5); // 10
triple(5); // 15
// カリー化
const add = (a) => (b) => a + b;
const add5 = add(5);
add5(3); // 8
add5(7); // 12
// 関数合成
const compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x);
const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x);
const process = pipe(
x => x.trim(),
x => x.toLowerCase(),
x => x.replace(/\s+/g, '-'),
);
process(' Hello World '); // 'hello-world'this の束縛
call、apply、bind、アロー関数での this
const obj = {
name: 'Alice',
// 通常の関数: this は呼び出し元に依存
greet() {
return `こんにちは、${this.name}!`;
},
// アロー関数: this を外側のスコープから継承
greetArrow: () => {
return `こんにちは、${this?.name}!`; // this は obj ではない
},
};
obj.greet(); // 'こんにちは、Alice!'
// call: 即時実行、引数をカンマ区切り
obj.greet.call({ name: 'Bob' }); // 'こんにちは、Bob!'
// apply: 即時実行、引数を配列で渡す
Math.max.apply(null, [1, 5, 3]); // 5
// bind: 新しい関数を返す(this を固定)
const greetAlice = obj.greet.bind({ name: 'Charlie' });
greetAlice(); // 'こんにちは、Charlie!'
// イベントリスナーでの注意
button.addEventListener('click', obj.greet.bind(obj));