0
0

More than 3 years have passed since last update.

PHPマニュアルのコード例をJavaScirptで再現してみる--無名関数編--

Last updated at Posted at 2020-08-20

はじめに

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()を使用してオブジェクトからプロパティ名(キー)を取り出して配列にします。

まとめ

なかなか良い学習法を見つけたかもしれません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0