【问题标题】:Best way to implement Javascript chaining in a library在库中实现 Javascript 链接的最佳方法
【发布时间】:2011-03-20 18:34:12
【问题描述】:

我正在创建一个 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() 函数,我无法以这种方式提取结果值。于是我想了一下这个问题,想出了两个半解决方案。

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

但是链接需要另外两个方法,这使得事情的可读性大大降低:

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

所以基本上我只是在寻找在我的库中实现链接的最佳方法。理想情况下,我正在寻找可以使用任意数量的方法并且不需要以不雅的方式终止链的东西。

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

【问题讨论】:

  • 我建议看看 jQuery 实现链接的方式。
  • 你会发现underscore.js.chain实现了你的第二个

标签: javascript chaining


【解决方案1】:

为什么不引入一个 private 变量并着手处理呢?我想这更方便。另外,拥有一个最终返回计算值的纯“getter”可能是个好主意。这可能如下所示:

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

您显然不能在 getter 函数 中返回 Object。所以你需要一些方法来结束链接并返回一个值。

【讨论】:

  • 嗯,我想这会奏效。绝对是迄今为止我见过的最好的提案。
  • 我认为这实际上行不通。您正在设置 p 而不是 value。应该返回 7
  • @nathan gonzales:我的错,修正了错字。
  • 冷静下来,我没有复制你的答案,我只是自己想出了相同的解决方案。我删除了我的答案。
【解决方案2】:

在某些情况下,它确实需要类似于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;
  }
}

通过向对象添加valueOftoString 函数,您可以访问其原始值。也就是说,您可以执行以下操作:

var num = V(0).add(1).sub(2), another_num = 3 + num; // num = -1 and another_num = 2;

【讨论】:

    【解决方案3】:

    我会将豪驰的优秀答案修改如下:

    如果你有很多 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);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-27
      • 1970-01-01
      • 1970-01-01
      • 2020-09-18
      • 1970-01-01
      相关资源
      最近更新 更多