Best way to implement javascript chaining in a library

I am creating a JavaScript library. I am trying to implement a chain.

0: what I first encountered:

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

Using this method, I can easily hide the chain:

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

Unfortunately, the result is always a complete V () function, so I cannot extract the resulting value this way. Therefore, I thought a little about this problem and came up with two half-solutions.

1: go to the last method

 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 the flag to the last method used:

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

While this works fine, it requires code repetition and makes the chain less readable, and my code less elegant.

2: Using the start () and end () methods

 _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 perform single operations without code:

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

But the chain requires two more methods, making things much less readable:

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

So, I'm just looking for the best way to implement chaining in my library. Ideally, I'm looking for something where I can use any number of methods and do not need to interrupt the chain in inelegant ways.

 V(3).add(7).sub(5) // 5, perfect chaining 
+4
source share
3 answers

Why not introduce a private variable and work on it? I think this is even more convenient. Plus, it is probably a good idea to have a clean getter that finally returns the calculated value. It might look like this:

 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 an Object in a getter function. So you need some kind of method when the chain ends and returns a value.

+11
source

In some cases, it needs something similar to end , but in your simple arithmetic example it is not.

 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 an object, you can access its primitive value. 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; 
+6
source

I would correct Haochi with an excellent answer as follows:

Using a prototype will be more efficient if you have many V objects and in the toString function, I call the toString common number with any arguments you want to give.

 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); } } 
+2
source

Source: https://habr.com/ru/post/1344484/


All Articles