What's the benefit of function composition implementation in libs like underscore, lo-dash and others, similar to this one:
var compose = function() {
var funcs = arguments;
return function() {
var args = arguments;
for (var i = funcs.length; i --> 0;) {
args = [funcs[i].apply(this, args)];
}
return args[0];
}
};
var c = compose(trim, capitalize);
in comparison to this:
var c = function (x) { return capitalize(trim(x)); };
The latter is much more performant.
For one, it's easier to read. Performance is rarely more important than that. Also, you could make a dedicated arity 2 function with nearly the same performance.
The other benefit is the composition can be easily changed at runtime. You can create versions that trim before capitalization, capitalize before trimming, trim only, capitalize only, or neither, without having to explicitly specify every single combination in the code. This can greatly simplify your code sometimes. Runtime composition is one of those things you never knew you always wanted.
For example:
var c = function(x) {return x;} // identity
var onTrimClick = function() {c = compose(c, trim);}
var onCapitalizeClick = function() {c = compose(c, capitalize);}
var onSomethingElseClick = function() {c = compose(c, somethingElse);}
This lets you create a composed function c at runtime based on what the user clicks and in what order.
//A simple way to understand javascript function composition =>
function composition(...fun) {
return function (value) {
var functionList = fun.slice();
while (functionList.length > 0) {
value = functionList.pop()(value);
}
return value;
}
}
function mult2(value) {
return value * 2;
}
function mult3(value) {
return value * 3;
}
function mult5(value) {
return value * 5;
}
var composedFun = composition(mult2, mult3, mult5);
console.log(composedFun);
console.log(composedFun(1));
console.log(composedFun(2));
Related
I am accepting an infinite amount of arguments and looping through whatever the user provides. I would like to incorporate an options object into this module, but I am not sure how that would work. Would this code just see the options object as one of the normal params?
module.exports = function () {
var args = Array.prototype.slice.call(arguments);
var masterObject = [];
args.forEach(function (array) {
array.map(function (item) {
var found = false;
for (var i = 0; i < masterObject.length; i++) {
if (masterObject[i].word === item.word) {
masterObject[i].count += item.count;
found = true;
}
}
if (!found) {
masterObject.push(item);
}
});
});
return masterObject;
};
Well, you need to decide between
var mymodule = require('mymodule')(opts);
mymodule(1, 2, 3);
and
var mymodule = require('mymodule');
mymodule(1, 2, 3, opts);
or something else. The first one:
module.exports = function (opts) {
return function() {
var args = Array.prototype.slice.call(arguments);
// ...
};
};
The second one:
module.exports = function (opts) {
var args = Array.prototype.slice.call(arguments);
opts = args.pop();
// ...
};
I like Amadan's response to this problem, I just wanted to add a related note:
What I see more often than not: APIs that accept an infinite number of values, AND accept options, will use the combination of an array (to contain the n-length values) and an object to pass in the options.
This way you don't need any voodoo, and your API is super clean:
module.exports = function (array, opts) {
// parse your options
opts = opts || {};
// loop over array
array.forEach(item => {
// to infinity, and beyond!
});
}
If you want to go crazy, and can use ES6 Rest Parameters, but if you did that, the options parameter would have to be supplied first (and if the user didn't have any options to pass, they would have to use null or an empty object, which could be weird for some APIs, but it's a possible way to approach this problem):
module.exports = function (opts, ...args) {
// do something with your options
opts.foo = opts.foo || true;
// now loop through your infinite args
args.forEach(item => {
console.log(item);
});
}
I'm just getting into functional programming and i'm having a hard time figuring out how to do this (if it's even worth the trouble). I've looked into currying and am not sure if this is the direction I need to go?? Or pipelines?
I would like to start with a value and then pipe it through different functions. Underscore has the 'chain' method which is similar. However I don't want to use prototypes to do this. I realize the solution might not match my target syntax.
Elm has the |> syntax (below) which is really nice to look at
// what i'd like to do (or similar) in JS *without using prototype*
num = ("(123) 456-7890")
.removeDashes()
.removeParens()
.removeSpaces()
// what elm does
"(123) 456-7890"
|> removeDashes
|> removeParens
|> rem
// functions I wrote so far
removeDashes = function(str) {
return str.replace(/-/g, '');
};
removeParens = function(str) {
return str.replace(/\(|\)/g, '');
};
removeSpaces = function(str) {
return str.replace(/\s/g, '');
};
// what i'm currently doing
num =
removeDashes(
removeParens(
removeSpaces(
"(123) 456-7890"")));
If you want to get you're feet wet with functional programming in JavaScript I'd advice you to use a library like Underscore, Lodash or Ramda. Which all have a compose/pipe functionality. Most of the times you'd want to combine it with some form of partial application which those libraries also provide.
Anyway it's a nice exercise to try to implement it yourself.
I would solve it like this...
/* Asumes es5 or higher */
function pipe (firstFn /* ...restFns */) {
var _ = null;
var _slice = Array.prototype.slice;
var restFns = _slice.call(arguments, 1) || [];
return function exec_fns() {
var args = _slice.call(arguments, 0, 1);
return restFns.reduce(function(acc, fn) {
return fn.call(_, acc);
}, firstFn.apply(_, args));
}
}
removeDashes = function(str) {
return str.replace(/-/g, '');
};
removeParens = function(str) {
return str.replace(/\(|\)/g, '');
};
removeSpaces = function(str) {
return str.replace(/\s/g, '');
};
console.log(pipe(
removeDashes,
removeParens,
removeSpaces
)("(123) 456-7890") == "1234567890")
Also Functional JavaScript by Fogus is a nice resource to dig deeper into this style of programming
There are different ways to tackle this problem, and you've offered references in underscore and Elm.
In Elm, curried functions are an important part of the equation. As every function receives a single argument, you can build chains with some of them partially applied, waiting for the argument you're weaving in with the pipeline. The same applies to Haskell, PureScript and languages of their ilk.
Reproducing that ipsis literis in JavaScript requires a little bit of sugar — you can use a sweet.js macro to get a source transformation that does it.
Without sugar, it can go many ways. Maybe one way to explore is using generators, passing the bits of the resolved chain down until you get a non-function value.
Like hindmost said, look into using prototypes. The string prototype allows you to add class-level functionality to all strings:
String.prototype.removeParens = function() {
this = this.replace(/\(|\)/g, '');
}
This lets you do things like this:
var myString = "(test)";
myString.removeParens();
And once you add the other functions to the String prototype you can simply chain the function calls like this:
myString.removeDashes().removeParens().removeSpaces();
etc.
You can create the pipe function in one line, with good readability:
const pipe = (...fns) => fns.reduce((v, f) => v.constructor === Function ? v() : f(v));
and it would be used in this way:
var numResult = pipe('(123) 456-7890', removeDashes, removeParens, removeSpaces);
var pipe = (...fns) => fns.reduce((v, f) => v.constructor === Function ? v() : f(v));
function removeDashes(str) {
return str.replace(/-/g, '');
}
function removeParens(str) {
return str.replace(/\(|\)/g, '');
}
function removeSpaces(str) {
return str.replace(/\s/g, '');
}
console.log(
'result:', pipe('(123) 456-7890', removeDashes, removeParens, removeSpaces)
);
Attention: this function needs a platform with support for the spread operator ....
Just in case, i've created a module for this with support for async functions (Promises) and it also works on older/legacy platforms that can't use the spread ...
https://github.com/DiegoZoracKy/pipe-functions
The easiest way is to really just add those to the prototype chain, but you can do that with an object. Here's an easy example:
function MyString( str ){
var value = str.toString();
return {
removeDashes: function() {
value = value.replace(/-/g, '');
return this;
},
removeParens: function() {
value = value.replace(/\(|\)/g, '');
return this;
},
removeSpaces: function() {
value = value.replace(/\s/g, '');
return this;
},
toString: function (){
return value;
},
valueOf: function (){
return value;
}
};
}
You can later on do this:
var clean = (new MyString('This \\(Is)\/ Dirty'))
.removeDashes()
.removeParens()
.removeSpaces();
This way, you will keep your prototype clean. To retrieve a non-object value, just run the toStrong() method, toValue() or do anything with the value (contatenating 1, divide it, anything!).
Here's a solution I found with lodash, it allows you to mixin your own functions and then use them against chain:
...
removeSpaces = function(str) {
return str.replace(/\s/g, '');
};
_.mixin({
removeSpaces: removeSpaces,
removeParens: removeParens,
removeDashes: removeDashes
});
num = _.chain("(123) 456-7890")
.removeSpaces()
.removeParens()
.removeDashes()
.value()
Not a very serious suggestions, but one that will work:
var update = pipe()(removeDashes >> removeParens >> removeSpaces);
update("(123) 456-7890"); //=> "1234567890"
This is based upon this implementation of pipe:
var pipe = function() {
var queue = [];
var valueOf = Function.prototype.valueOf;
Function.prototype.valueOf = function() {
queue.push(this);
return 1;
};
return function() {
Function.prototype.valueOf = valueOf;
return function(x) {
for (var i = 0, val = x, len = queue.length; i < len; i++) {
val = queue[i](val);
}
return val;
}
};
};
You can see more in slide 33 of my talk on functional composition in js.
As the others have said, adding the functions to the String prototype is a valid and short solution. However, if you don´t want to add them to String prototype or if you want to perform in the future more complex functions, another option is to make a wrapper to handle this:
function SpecialString(str){
this.str = str;
this.removeDashes = function() {
this.str=this.str.replace(/-/g, '');
return this;
};
this.removeParens = function() {
this.str=this.str.replace(/\(|\)/g, '');
return this;
};
this.removeSpaces = function() {
this.str=this.str.replace(/\s/g, '');
return this;
};
return this;
}
num = new SpecialString("(123) 456-7890").removeDashes().removeParens().removeSpaces();
console.log(num) // 1234567890
I'm creating a module that accepts a data set and an integer n and recursively fills that dataset with n products at a time, after the first call, the function loses its scope and errors out. Why, And what's the best practice for fixing this?
Code:
function ProductFactory(){
var bigArr = [0,1,2,3,4,5,6,7,8,9];
var smallArr = [1,2,3,4];
return {
getProductList: getProductList,
getAllProducts: getAllProducts
};
function getProductList(start, size){ return start < 5 ? bigArr : smallArr }
function getAllProducts(batchSizeRequested, dataSet) {
var startPage = dataSet.length / batchSizeRequested;
var productBatch = this.getProductList(startPage, batchSizeRequested);
dataSet = dataSet.concat(productBatch);
if (productBatch.length === batchSizeRequested)
getAllProducts(batchSizeRequested, dataSet);
}
}
var productGetter = new ProductFactory();
productGetter.getAllProducts(10, []);
1) First of all you shouldn't call getProductList using this, in this case you can just call it as it is, because getProductList is not a function that was assigned directly to this object. It is just a closure that uses local variables in it's code. If you want to call function using this, you should assign it using this, for example this.getProductList = function() {}
2) I don't think there are other scoping problems except redundant this, but I found another issue, though.
You are not actually return anything from your function, plus recursive call does not have an exit point.
Fixed code looks like this.
function ProductFactory(){
var bigArr = [0,1,2,3,4,5,6,7,8,9];
var smallArr = [1,2,3,4];
return {
getProductList: getProductList,
getAllProducts: getAllProducts
};
function getProductList(start, size){ return start < 5 ? bigArr : smallArr }
function getAllProducts(batchSizeRequested, dataSet) {
var startPage = dataSet.length / batchSizeRequested;
var productBatch = getProductList(startPage, batchSizeRequested);
dataSet = dataSet.concat(productBatch);
if (productBatch.length === batchSizeRequested) {
return getAllProducts(batchSizeRequested, dataSet);
} else {
return dataSet;
}
}
}
var productGetter = ProductFactory();
var products = productGetter.getAllProducts(10, []);
console.log(products)
The typical approach to a function call like this is to assign an external value to this (typically called self):
function ProductFactory(){
...
var self = this;
function getAllProducts(batchSizeRequested, dataSet) {
...
getAllProducts.apply(self, [batchSizeRequested, dataSet]);
}
}
In this case, however, please try to remember that you have defined a closure function getAllProducts that is only privately accessible internal to the constructor. Instead you should probably do:
function ProductFactory(){
...
var self = this;
this.getAllProducts = function(batchSizeRequested, dataSet) {
...
self.getAllProducts(batchSizeRequested, dataSet);
}
}
I recently had to refactor a chunk of javascript that is using YUI.
So, originally it was something like this:
YAHOO.namespace('space.time');
YAHOO.space.time = (function() {
var b = document.getelementbyid("aifdsgyalierg");
function c(b) {
var a = new YAHOO.util.Anim(d, b); //just assume the parameters are correct here
a.method = YAHOO.util.Easing.easeOut;
a.animate();
};
return { c:c };
})();
For the sake of being able to inject dependencies, i refactored it to the below:
YAHOO.namespace('space.time');
YAHOO.namespace('space.timefn');
YAHOO.space.timefn = function(yuianim) {
var b = document.getelementbyid("aifdsgyalierg");
function c(d) {
var a = new yuianim(d, b); //just assume the parameters are correct here
a.method = YAHOO.util.Easing.easeOut;
a.animate();
};
return { c:c };
};
YAHOO.space.time = YAHOO.space.timefn(YAHOO.util.Anim);
So..
1) Ignoring any committed fallacies.. Will the behaviour of the two snippets differ?
2) What fallacies have i committed?
For a personal challenge, I'm implementing LINQ in JavaScript (well, a set of functions with LINQ-like functionality). However, as of right now, the functions are processing the data immediately; that's correct behavior for some functions (such as Sum or Aggregate), but incorrect for others (such as Select or While).
I'm curious if there's a construct in JavaScript that could get me the same behavior as in .Net, where no real processing happens until the collection is enumerated or a function with immediate execution is used.
Note: I believe this task (implementing LINQ in JS) has already been done. That's not the point. This is a challenge to myself from myself, which is likely to help me increase my understanding of LINQ (and, coincidentally, JS). Beyond personal edification, I'm going to be using LINQ for my job soon, may use JS for my job depending on the needs of individual projects, and I use JS for some things outside of work.
Edit: It seems I've attracted people unfamiliar with LINQ, so I suppose I should give some explanation on that front. LINQ is Language-INtegrated Query, something from .Net. LINQ allows for SQL-like queries on many data sources (including actual SQL relational databases), such as LINQ to Objects, which is what I'm trying to achieve.
One of the features of LINQ is deferred execution on many of the methods. If I have a collection customers and call var query = customers.Where(c => c.Age > 40); (or what it would end up being in JS, var query = customers.Where(function (c) { return c.Age > 40; });), the return value is an interface type, and the actual processing of the collection (returning the subset of the collection containing only customers older than 40) hasn't happened yet. When I use one of the methods without deferred execution (eg, query.First() or query.ToArray()), then all of the deferred processing happens. This could be a chain, such as customers.Where(...).Skip(5).Select(...).OrderBy(...) (each "..." being a function).
The upshot is that code like this:
var collection = [1, 2, 3, 4, 5];
var query = collection.Where(function (n) { return n % 2 == 0; });
collection.push(6);
alert(query.Max());
Would result in "6".
As an addendum, I'm currently implementing this project by prototyping my methods onto both Object and Array, iterating over the elements of this, and skipping any elements which are functions. Something like making an Enumerable class may be superior (and in fact may be required for my deferred execution plan, if something like returning a function or an anonymous object is required), but that's what I've currently got. My functions generally appear as something along these lines:
Object.prototype.Distinct = Array.prototype.Distinct = function (comparer) {
comparer = comparer || function (a, b) { return a == b; };
var result = [];
for (var idx in this) {
var item = this[idx];
if (typeof item == "function") continue;
if (!result.Contains(item, comparer)) result.push(item);
}
return result;
};
Fundamentally what you need to do is return objects from your functions rather than performing operations. The objects you return will contain the code necessary to perform the operations in the future. Consider an example use case:
var myCollection = [];
for(var i = 0; i < 100; i++) { myCollection.push(i); }
var query = Iter(myCollection).Where(function(v) { return v % 2 === 0; })
.Skip(5).Select(function(v) { return v*2; });
var v;
while(v = query.Next()) {
console.log(v);
}
We expect as output:
20
24
28
...
188
192
196
In order to do that we define the methods .Where(), .Skip(), and .Select() to return instances of classes with overridden versions of the .Next() method. Working code that supports this functionality: ( set trace to true to observe that the execution order is lazy)
var trace = false;
function extend(target, src) {
for(var k in src) {
target[k] = src[k];
}
return target;
}
function Iter(wrapThis) {
if(wrapThis.Next) {
return wrapThis;
} else {
return new ArrayIter(wrapThis);
}
}
Iter.prototype = {
constructor: Iter,
Where: function(fn) { return new WhereIter(this, fn); },
Skip: function(count) { return new SkipIter(this, count); },
Select: function(fn) { return new SelectIter(this, fn); }
};
function ArrayIter(arr) {
this.arr = arr.slice();
this.idx = 0;
}
ArrayIter.prototype = extend(Object.create(Iter.prototype),
{
constructor: ArrayIter,
Next: function() {
if(this.idx >= this.arr.length) {
return null;
} else {
return this.arr[this.idx++];
}
}
});
function WhereIter(src, filter) {
this.src = src; this.filter = filter;
}
WhereIter.prototype = extend(Object.create(Iter.prototype), {
constructor: WhereIter,
Next: function() {
var v;
while(true) {
v = this.src.Next();
trace && console.log('Where processing: ' + v);
if(v === null || this.filter.call(this, v)) { break; }
}
return v;
}
});
function SkipIter(src, count) {
this.src = src; this.count = count;
this.skipped = 0;
}
SkipIter.prototype = extend(Object.create(Iter.prototype), {
constructor: SkipIter,
Next: function() {
var v;
while(this.count > this.skipped++) {
v = this.src.Next();
trace && console.log('Skip processing: ' + v);
if(v === null) { return v; }
}
return this.src.Next();
}
});
function SelectIter(src, fn) {
this.src = src; this.fn = fn;
}
SelectIter.prototype = extend(Object.create(Iter.prototype), {
constructor: SelectIter,
Next: function() {
var v = this.src.Next();
trace && console.log('Select processing: ' + v);
if(v === null) { return null; }
return this.fn.call(this, v);
}
});
var myCollection = [];
for(var i = 0; i < 100; i++) {
myCollection.push(i);
}
var query = Iter(myCollection).Where(function(v) { return v % 2 === 0; })
.Skip(5).Select(function(v) { return v*2; });
var v;
while(v = query.Next()) {
console.log(v);
}
You also may want to look into "string lambdas" to make your queries much more readable. That would allow you to say "v*2" instead of function(v) { return v*2; }
I am not entirely clear on what exactly you wish to do, but I think what you should look into is the defineProperty method. What you would probably wish to do is then to redefine the .length property and execute the code only once it's read. Or if you want to do it only once the property itself is read do it at that point. Not sure how LINQ works or even what it is, so that's why I am a bit vague. Either way, with defineProperty you can do something like
Object.defineProperty(o, "a", { get : function(){return 1;});
Allowing you to do actions only once the property is accessed (and you can do a lot more than that as well).