5

JavaScript ライブラリを作成しています。私はチェーンを実装しようとしています。

0: 最初に思いついたこと:

function V(p) {
  return {
    add : function(addend) { return V(p + addend); },
    sub : function(subtra) { return V(p - subtra); },
  };
}

この方法を使用すると、簡単に連鎖できます。

V(3).add(7).sub(5) // V(5)

残念ながら、結果は常にラップされた V() 関数です。結果の値をこの方法で抽出することはできません。そこで、この問題について少し考えて、2 つの半解決策を思いつきました。

1: 最後のメソッドにフラグを渡します

function V(p, flag) {
  if(flag)
    return p;
  else
    return {
      add : function(addend, flag) { return V(p + addend, flag); },
      sub : function(subtra, flag) { return V(p - subtra, flag); }
    };
}

このメソッドを使用すると、最後に使用したメソッドにフラグを渡すことでチェーンを終了できます。

V(3).add(7).sub(5, true) // 5

これは問題なく機能しますが、コードの繰り返しが必要になり、チェーンが読みにくくなり、コードが洗練されなくなります。

2: start() および end() メソッドの使用

_chain = false;
function V(p) {
  function Wrap(w) {
    return (_chain) ? V(w) : w;
  }
  return {
    add : function(addend) { return Wrap(p + addend); },
    sub : function(subtra) { return Wrap(p - subtra); },
    start : function() { _chain = true; },
    end : function() { _chain = false; return p; }
  };
}

このメソッドを使用すると、コードを追加せずに単一の操作を実行できます。

V(3).add(7) // 10

しかし、連鎖にはさらに 2 つの方法が必要であり、読みにくくなります。

V(3).start().add(7).sub(5).end() // 5

したがって、基本的には、チェーンをライブラリに実装するための最良の方法を探しているだけです。理想的には、任意の数のメソッドを使用でき、洗練されていない方法でチェーンを終了する必要がないものを探しています。

V(3).add(7).sub(5) // 5, perfect chaining
4

3 に答える 3

12

プライベート変数を導入してそれに取り組んでみませんか?それはもっと便利だと思います。さらに、最終的に計算値を返す純粋な「ゲッター」を用意することをお勧めします。これは次のようになります。

function V(p) {
  var value = p;

  return {
    add: function(addend) {
      value += addend;
      return this;
    },
    sub: function(subtra) {
      value -= subtra;
      return this;
    },
    get: function() {
      return value;
    }
  };
}

console.log(V(3).add(7).sub(5).get()); // 5

明らかにゲッター関数Objectでを返すことはできません。したがって、チェーンが終了して値を返すメソッドが必要です。

于 2011-03-20T18:39:46.210 に答える
5

に似たものが必要な場合もありendますが、単純な算術の例ではそうではありません。

function V(initial_val){
  if(!(this instanceof V)){
    return new V(initial_val);
  }

  var num = initial_val || 0;

  this.set = function(val){
    num = val;
    return this;
  }
  this.add = function(val){
    num += val;
    return this;
  }
  this.sub = function(val){
    num -= val;
    return this;
  }
  this.valueOf = function(){
    return num;
  }
  this.toString = function(){
    return ""+num;
  }
}

valueOf関数と関数をオブジェクトに追加することtoStringで、そのプリミティブ値にアクセスできます。つまり、次のようなことができます。

var num = V(0).add(1).sub(2), another_num = 3 + num; // num = -1 and another_num = 2;
于 2011-03-20T18:52:33.560 に答える
3

Haochi の優れた回答を次のように修正します。

多くの V オブジェクトがあり、toString 関数で、任意の引数を指定して一般的な数値 toString を呼び出す場合は、プロトタイプを使用する方が効率的です。

function V (n) {
  if (!(this instanceof V)) {
    return new V (n);
  }

  this.num = +n || 0;
  return this;
}

V.prototype = {
  set: function (val) {
    this.num = val;
    return this;
  },
  add: function (val) {
    this.num += val;
    return this;
  },
  sub: function (val) {
    this.num -= val;
    return this;
  },
  valueOf: function () {
    return this.num;
  },
  toString: function () {
    return this.num.toString.apply (this.num, arguments);
  }
}
于 2011-03-20T19:33:22.003 に答える