2

D3.js を学習しているときに、再利用可能なコード単位の背後にある主なデザイン パターンを説明するブログ投稿に出くわしました。関連するコードを以下に再現しました。以下に示すパターンは、D3 コードベースおよびプラグインで使用される方法とまったく同じです ()。

このコードに関する私の 1 つの問題は、プロパティのコピーと貼り付けが非常に多いことです。JavaScript は関数型言語なので、ボイラープレート コードをリファクタリングできると思っていましたが、それを行う方法が思いつきません。argumentsパラメータとパラメータを共通の関数に渡すのは簡単ですが、プロパティとプロパティvalueへの参照を保持する方法が見つかりません。widthheight

function chart() {
  var width = 720, // default width
      height = 80; // default height

  function my() {
    // generate chart here, using `width` and `height`
  }

  my.width = function(value) {
    if (!arguments.length) return width;
    width = value;
    return my;
  };

  my.height = function(value) {
    if (!arguments.length) return height;
    height = value;
    return my;
  };

  return my;
}

これが実際の D3 コードベースで行われているという事実は、リファクタリングが可能かどうか疑問に思いますが、これが優先度の高い問題ではないという単純な問題であることを願っています (そして、新しい貢献者はこれを行っています)。以前はそうだったからです)。

私が探しているのは、基本的にすべてのアクセサーの本体を次のものに置き換えることです:

my.height = function(value) {
  return getSet(arguments, value, whatever);
};

呼び出し用のボイラープレートがまだいくつかありますが、少なくともロジックは一元化されており、必要に応じて 1 か所でのみ更新できます。

4

2 に答える 2

1

getSetのスコープで定義するchartと、クローズド オーバー変数にもアクセスできます。問題は、これらの変数に名前文字列でアクセスできないことです (ある種の を使用しない限りeval)。

untestedオブジェクトにすべてのプライベート変数をラップすることで、これを回避できます。

function chart() {
    var props = {
        width: 720, // default width
        height: 80 // default height
    }

    function my() {
        // generate chart here, using `width` and `height`
    }

    my.height = function(value) {
        // Call getSet with current my instance as this, 
        // 'height' as the first argument, then value
        return getSet.apply(this, arguments.slice().unshift('height'));
    };

    // Works just like your current accessors, on the props object
    function getSet(property, value) {
        if (arguments.length > 1) return props[property];
        props[property] = value;
        return this;
    }

    return my;
}

問題は、これが各プロパティに対していくつかの同様のアクセサを記述するよりもはるかに短くないことです。現在のアクセサーは、プライベート変数を事実上パブリックにするので、それらを捨てて代わりにパブリック変数を使用しないのはなぜですか?

于 2013-02-19T04:11:15.357 に答える
0

すでに提供されている代替ソリューションは、関数を返す「プロパティ」関数を定義することです。

function property (v) {
    return function (_) {
    if(!arguments.length)
            return v;
        v = _;
    return this;
};
}

したがって、次のように言えます。

function chart() {
    chart.width = property.call(chart, 500);
    chart.height = property.call(chart, 500);

    chart.render = function() {
    //render logic goes here
    };

    return chart;
}

私はこれを完全に信用することはできません-ソースは実際にはマイク・ボストックだったと思います(ただし、元の投稿へのリンクが見つかりません)

私は多くのモジュールでこの「プロパティ」機能を使用しています。これにより、煩わしい入力作業が大幅に軽減されます。入力値が変更されたときにイベントを発行するように簡単に拡張できます。

于 2013-03-25T22:12:05.887 に答える