先日 closure を使った オブジェクト指向的なコードを JavaScript で書くというデモをする機会があり、これはその覚書です。
ES6 などでは そもそも class が使えるので、ここで説明する方法で記述することはないと思いますが、 InDesign などの ExtendScript では未だに ES3 レベルで class は使えないので、その向きには有効かと思います。
Product というクラスを使った Java(Groovy)ではごく普通のコード。
製品名と価格を渡して Prodcut オブジェクトを生成し、render() を呼ぶと 製品情報を出力する機能を持つ。
class Product {
private final String name
private final int price
private final int priceWithTax
Product(String name, int price, float taxRate){
this.name = name
this.price = price
this.priceWithTax = (price * (1.0f + taxRate)) as int
}
private static String addComma(int value){
def m = ("${value}" =~ /(\d+)(\d{3})/)
if( m.find() ){
return "${m.group(1)},${m.group(2)}"
}
return "${value}"
}
String render(){
return "- ${name} : ${addComma(price)}円 (税込み ${addComma(priceWithTax)}円)"
}
}
def taxRate = 0.1f
def macmini = new Product('mac mini', 72_800, taxRate)
def macbookAir = new Product('macbook air', 104_800, taxRate)
def macbookPro = new Product('macbook pro', 134_800, taxRate)
[macmini, macbookAir, macbookPro].each {
println it.render()
}
実行すると結果はこれ:
- mac mini : 72,800円 (税込み 80,080円)
- macbook air : 104,800円 (税込み 115,280円)
- macbook pro : 134,800円 (税込み 148,280円)
JavaScript で class を使わないので Product クラスを makeProduct という名前の 関数 に変えています.
const makeProduct = function(name, price, taxRate){
const addComma = function(value){
String(value).match(/(\d+)(\d{3})$/)
return RegExp.$1 + "," + RegExp.$2;
};
const priceWithTax = Math.round( price * (1.0 + taxRate) );
return function(){
return `- ${name} : ${addComma(price)}円 (税込み ${addComma(priceWithTax)}円)`;
};
};
const taxRate = 0.10;
const macmini = makeProduct('mac mini', 72_800, taxRate);
const macbookAir = makeProduct('macbook air', 104_800, taxRate);
const macbookPro = makeProduct('macbook pro', 134_800, taxRate);
[macmini, macbookAir, macbookPro].forEach( function(item){
console.log(item());
});
makeProduct 関数は 無名の関数を返し、その無名の関数内に name, price, priceWithTax という変数を捕捉(close)している、ということだと思う。 Closures の詳細は JavaScript/Closures などを御覧ください。
JavaScript を VSCode でデバッグする場合、プロジェクトディレクトリの .vscode/launch.json に以下を書く。 これで VSCode 上で JavaScript のデバッグできるのはとても楽です。
{
"version": "1.0.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "file",
"program": "${file}",
"stopOnEntry": false
}
]
}