Underscore.js _.tap () function - what is a chain of methods?

The Underscore.js documentation explains that the _.tap() function “selects” the method chain. http://underscorejs.org/#tap

I am having problems with their example:

 _.chain([1,2,3,200]) .filter(function(num) { return num % 2 == 0; }) .tap(alert) .map(function(num) { return num * num }) .value(); => // [2, 200] (alerted) => [4, 40000] 

What is the chain of methods in this context? I always thought of the method chain as the concept of a chain of methods from each other: object.foo().bar().baz() .

I saw examples using this method: module.exports = _.tap {}, (connectors) -> , so does it "touch" the object literal in the method chain?

+4
javascript chaining method-chaining
source share
4 answers

From a great guide :

Chaining
[...]
Calling the chain will cause all calls to future methods to return wrapped objects. When you finish the calculation, use the value to get the final value.

So the chain in the Underscore context is the same as the chain elsewhere, except that you are binding Underscore methods on a wrapped object. You start by calling _.chain to get your wrapper:

 _(obj).chain() 

then you call the Underscore methods when returning _.chain , and they also return wrapped objects:

 _(obj).chain() .filter(function(x) { ... }) .map(function(x) { ... }) ... 

and finally you call _.value to expand the wrapper chain:

 var result = _(obj).chain() .filter(function(x) { ... }) .map(function(x) { ... }) ... .value(); 

Return to _.tap . All tap does this :

 _.tap = function(obj, interceptor) { interceptor(obj); return obj; }; 

so that it calls the passed function, interceptor , when it repeats and returns what is being executed, without any action. _.tap same as:

 .map(function(x) { f(x); return x }) 

but it makes your intention clear. In fact, _.tap allows _.tap to look into data passing through a chain of methods without changing that data.

+9
source share

I agree that the example in the documents is stupid, because an alert iterated object will never be what you would like to do in a real situation (if you did not debug and did not want to know the state of the object between 2 chain methods - but in this case, probably just warned [object Object] ; console.log would be more appropriate but would not work as intended [but I got distracted]). Here is an example of a non-targeted workflow:

 var x = { a: 1, b: 2, c: 3 }; x = _.filter( x, function( value ){ return ( value % 2 === 0 ); } ); x.length = _.size( x ); x = _.pairs( x ); 

This scenario really lends itself to a chain: all of the above code essentially creates and periodically modifies one object. Chaining makes this clear and stops the continuous execution of tasks. The only problem is the line in which I declare length -, which does not fit neatly in the chain, as this is the only statement that does not just invoke the underline method of the object and assigns the result to that object. And here comes the tap : you want to do something that doesn't allow you to easily cling inside the chain. Here's what a chain with chain looks like:

 var x = _ .chain( { a: 1, b: 2, c: 3 } ) .filter( function( value ){ return ( value % 2 === 0 ); } ) .tap( function( x ){ x.length = _.size( x ); } ) .pairs() .value(); 
+8
source share

A method chain, as you described, links methods to each other. A key detail regarding _.tap is that the results of each method are passed to the next .

_. tap allows you to insert a method whose results are not passed through . The result of the previous method is passed to the next _tap method. This allows you to process intermediate results in a chain without changing the results of the chain.

In your example, alert will break the chain if it is called by itself, since it does not return anything. Using _.tap results in the results of the previous method ( filter(function(num) { return num % 2 == 0; }) ) being passed to the next method ( map(function(num) { return num * num }) )

+1
source share

The chain in your example is filter().tap().map() :

  • _.chain([1,2,3,300]) wraps an array in an underscore that has methods such as filter , tap , map , value , etc.
  • .tap(alert) expands the result from filter() , calls alert() with the object expanded, then terminates it again and returns it
  • .value() returns a wrapped object (minus the wrapper).
+1
source share

All Articles