クロージャの練習のために、Closure Design Patterns の記事で紹介されている Groovy のコードを JavaScript に書き換えてみました。Groovy、Scala、Java の書籍を書いている Venkat Subramaniam さんのプレゼン資料が元ネタです。ES2015 で導入された const とアロー関数を使ったスタイルに取り組んでみました。
Babel のセットアップ
ターミナルでコードを実行するために babel-node をインストールします。
npm install -g babel-node
ES2015 を利用するために babel-preset-es2015 をローカルにダウンロードします。
npm install babel-preset-es2015
スクリプトを実行する際にオプションの --presets es2015
を指定します。
babel-node --presets es2015 test.js
Execute Around Method
const operations = (closure) => {
console.log('Open')
closure()
console.log('Close')
}
operations(() => console.log('Operation'))
Pluggable Behavior
const selectValues = (number, closure) => {
let list = []
for (let i = 0; i < number; i++) {
if (closure(i)) {
list.push(i)
}
}
return list
}
var ret = selectValues(10, n => n % 2 == 0)
console.log(ret)
Iterator Pattern
const listNumbers = closure => {
for (let i = 0; i < 4; i++) {
closure(i)
}
}
listNumbers(n => {
if (n < 3) {
console.log(n + ' は小さい数値')
} else {
console.log(n + ' は大きな数値')
}
})
Dynamical Conditional Execution
const isAdmin = user => {
return ['foo', 'bar'].indexOf(user) > -1
}
const greet = (user, successClosure, failClosure) => {
if (isAdmin(user)) {
successClosure()
} else {
failClosure()
}
}
greet('foo',
() => { console.log('Hi Admin!') },
() => { console.log('Hello User') }
)
Template Method Pattern
const withCustomer = (id, closure) => {
let customer = getCustomer(id)
closure(customer)
}
const getCustomer = id => {
let customers = [
{ id: 1 , name: 'foo'},
{ id: 2 , name: 'bar'}
]
for (let customer of customers) {
if (id === customer.id) {
return customer
}
}
return {id:null, id: null};
}
withCustomer(1, customer => {
console.log('Found customer ' + customer.name)
})
Loan Pattern
省略
Command Design Pattern
let count = 0
let commands = []
for (let i = 0; i < 10; i++) {
commands.push(() => count++)
}
console.log('count is initially ' + count)
commands.forEach(cmd => {
cmd()
})
console.log('did all commands, count is ' + count)
Strategy Pattern
const calcMult = (n, m) => n * m
const calcAdds = (n, m) => {
let result = 0
for (let i = 0; i < n; i++) {
result += m
}
return result
}
const calcStrategies = [calcMult, calcAdds]
calcStrategies.forEach(calc => {
console.log(10 === calc(5, 2))
})
Factory Pattern
const adder = (x, y) => x + y
const incrementer = adder.bind(null, 1)
console.log(5 === incrementer(4))
Method Combination
const sum = arr => arr.reduce((acc, value) => acc + value)
const first2 = arr => arr.slice(0, 2)
const take2andAdd = n => sum(first2(n))
console.log(3 === take2andAdd([1, 2, 3, 4, 5]))