简体   繁体   English

在库中实现Javascript链接的最佳方法

[英]Best way to implement Javascript chaining in a library

I'm creating a JavaScript library. 我正在创建一个JavaScript库。 I've been trying to implement chaining. 我一直在尝试实施链接。

0: What I first came up with: 0:我第一次提出的:

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

Using this method I can chain easily: 使用这种方法我可以很容易地链接:

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

Unfortunately the result is always a wrapped V() function, I am unable to extract the resulting value this way. 不幸的是,结果始终是一个包装的V()函数,我无法以这种方式提取结果值。 So I thought about this problem a bit and came up with two semi-solutions. 所以我想了一下这个问题并提出了两个半解决方案。

1: Passing flag to last method 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); }
    };
}

Using this method I can end the chain by passing a flag to the last method I use: 使用这种方法,我可以通过将标志传递给我使用的最后一个方法来结束链:

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

While this works just fine, it requires some code repetition and makes chaining less readable and my code less elegant. 虽然这很好用,但它需要重复一些代码,并且链接的可读性会降低,而且代码也不那么优雅。

2: Using start() and end() methods 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; }
  };
}

Using this method you can do single operations with no more code: 使用此方法,您可以执行单个操作,而无需更多代码:

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

But chaining requires two more methods, making things a lot less readable: 但链接需要两种方法,使得可读性低得多:

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

So basically I'm just searching for the best way to implement chaining into my library. 所以基本上我只是在寻找实现链接到我的库的最佳方法。 Ideally I'm looking for something where I can use any number of methods and don't need to terminate the chain in inelegant ways. 理想情况下,我正在寻找一些我可以使用任何方法的东西,而不需要以不优雅的方式终止链。

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

Why not introducing a private variable and working on that ? 为什么不引入一个私有变量并进行处理呢? I guess that is even more convinient. 我想这更方便。 Plus it's probably a good idea to have a pure "getter" which finally returns the computed value. 另外,拥有一个最终返回计算值的纯“getter”可能是一个好主意。 This could look like: 这可能看起来像:

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; }
    };
}

V(5).add(7).sub(5).get();  // 5

You cannot return the Object in a getter function obviously. 您显然无法在getter函数中返回Object So you need some method where the chaining ends and returns a value. 所以你需要一些链接结束并返回值的方法。

In some cases it does need to have something similar to end , but in your simple arithmetic example, it does not. 在某些情况下,它确实需要具有类似于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;
  }
}

By adding valueOf and toString functions to the object, you can access its primitive value. 通过将valueOftoString函数添加到对象,您可以访问其原始值。 That is, you can do something like: 也就是说,你可以这样做:

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

I would amend Haochi's excellent answer as follows : 我会将Haochi的优秀答案修改如下:

Using the prototype will be more efficient if you have many V objects and in the toString function I invoke the generic number toString with whatever arguments you care to give it. 如果你有很多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);
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM