##はじめに
PHPとJavaScript両方の勉強ができる方法はないものか考えてみたのですが、PHPマニュアルのコード例をJavaScriptで再現してみるのはどうか?と思い立ち、実際にやってみました。
##今回の題材
記念すべき(?)第1回目の題材は、無名関数のところに記載されていたコード例としました。以下はコード例の引用です。
PHPマニュアル 無名関数
<?php
// 基本的なショッピングカートで、追加した商品の一覧や各商品の
// 数量を表示します。カート内の商品の合計金額を計算するメソッド
// では、クロージャをコールバックとして使用します。
class Cart
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;
protected $products = array();
public function add($product, $quantity)
{
$this->products[$product] = $quantity;
}
public function getTotal($tax)
{
$total = 0.00;
$callback =
function ($quantity, $product) use ($tax, &$total)
{
$pricePerItem = constant(__CLASS__ . "::PRICE_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
array_walk($this->products, $callback);
return round($total, 2);
}
}
$my_cart = new Cart;
// カートに商品を追加します
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);
// 合計に消費税 5% を付加した金額を表示します
print $my_cart->getTotal(0.05) . "\n";
// 結果は 54.29 です
?>
消費税5%とは良い時代ですね・・・
色々勉強になりましたが、大切なのは変数のスコープでしょうか。
PHPのスコープにはスーパーグローバル、グローバル、ローカルの3種類があります。スーパーグローバルはここでは置いておいて、関数の外で定義された変数がグローバルスコープ、関数の中で定義された変数がローカルスコープとなります。グローバルスコープの変数は、何もなしには関数の中では使えません。
で、クロージャについては親スコープから変数を引き継ぐことができます(useを使用)。
親スコープから引き継いだ変数の値は、関数が呼び出された時の値ではなく、関数が定義された時点のものになるというのが注意点です。
また、今回登場している$totalは、金額の合計値を算出するために、クロージャに対し値渡しではなく参照渡しで渡します。
##JavaScriptで再現
では、早速JavaScriptで再現してみます。
class Cart {
static price = {
'butter': 1,
'milk': 3,
'eggs': 6.95
};
constructor() {
this.products = {};
}
add(product, quantity) {
this.products[product] = quantity;
}
getTotal(tax) {
let total = 0;
const callback = function(product, quantity) {
const pricePerItem = Cart.price[product];
total += (pricePerItem * quantity) * (tax + 1);
}
Object.keys(this.products).forEach((key) => {
callback(key, this.products[key]);
});
return Math.round( total * 100 ) / 100;
}
}
const my_cart = new Cart;
my_cart.add('butter', 1);
my_cart.add('milk', 3);
my_cart.add('eggs', 6);
console.log(my_cart.getTotal(0.05));
クラス定数はstaticキーワードを使い、オブジェクトとしてまとめました。
連想配列$productsは、JavaScriptのオブジェクトに対応するのでそのようにします。addメソッドはほぼ一緒の書き方でOKですね。
最後に、getTotalメソッドですが、PHPのクロージャははuseを使わないと$tax、$totalを使用できませんでしたが、JavaScriptでは関数内に変数が見つからない場合、親の関数に変数を探しにいくため、そういった必要がありません。
PHPのarray_walk()は、JavaScriptではmap()やforEach()に対応しているのでは?と思いました。ですが、これらのメソッドは配列に対してしか使えません。そこで、Object.keys()を使用してオブジェクトからプロパティ名(キー)を取り出して配列にします。
##まとめ
なかなか良い学習法を見つけたかもしれません。