I have n number of functions, each one takes a 'data' {Object} as argument. Each function return a {Boolean} based on the given argument.
I want to compose/chain these functions, what is the best way to accomplish that?
See code below.
var fn1 = function(data) {
return data.status === 404;
};
var fn2 = function(data) {
return data.url === 'any_url';
};
var composed = compose(fn1, fn2);
// The line below must return false:
composed({ status: 404, url: 'foobar'});
// The line below must return true:
composed({ status: 404, url: 'any_url'});
So you want to return true if all functions return true? That can be achieved with Array#every. We simply use Array#every on the array of functions and return the function's result in the callback:
function compose() {
var fns = Array.prototype.slice.call(arguments);
return function(obj) {
return fns.every(function(f) {
return f(obj);
});
};
}
function compose() {
var fns = Array.prototype.slice.call(arguments);
return function(obj) {
return fns.every(function(f) {
return f(obj);
});
};
}
var fn1 = function(data) {
return data.status === 404;
};
var fn2 = function(data) {
return data.url === 'any_url';
};
var composed = compose(fn1, fn2);
// The line below must return false:
console.log(composed({
status: 404,
url: 'foobar'
}));
// The line below must return true:
console.log(composed({
status: 404,
url: 'any_url'
}));
The advantage of this is that Array#every will stop as soon as one return value is false.
With ES6+:
function compose(...fns) {
return obj => fns.every(f => f(obj));
}
Note: compose is a poor choice of name for this because "composing functions" usually refers to passing the result of one function into the other function. I.e. compose(f, g)(x) would be the same as f(g(x)).
you could do something as simple as
function compose(data){
return fn1(data) && fn2(data)
}
this function will return true if all conditions(return values of your functions) are true
Related
I got asked this in an Interview and I couldn't solve it. Was wondering if any of you guys can help me.
fn("hello").fn("world").fn("!!!").fn();
function fn (str){
// Enter Solution Here
}
The solution should return 'hello world !!!'.
I tried method chaining and was able to get a partially right answer which is as follows:
function fn(str) {
var string = str;
this.fn1 = function(str1) {
string += " "+str1;
return this;
}
this.fn = function() {
console.log(string)
}
}
new fn("hello").fn1("world").fn1("!!!").fn();
but as you can see I cant get it to work unless I use fn1 as the function to concat the string. Any help will be appreciated, thanks.
Have the function return an object with one fn method. If, when you call it, it has an argument, update the string, otherwise return the string so you can log it.
function fn(str = '') {
return {
fn: function (s) {
if (s) {
str += ` ${s}`;
return this;
}
return str;
}
};
}
const output = fn('hello').fn('world').fn('!!!').fn();
console.log(output);
Additional documentation
Template/string literals
You could return an object with two properties, one for returning the complete string and another for collecting parts and retuning the object.
function fn(str) {
const
fns = {
fn: function () {
return str;
},
fn1: function (s) {
str += ' ' + s;
return fns;
}
};
return fns;
}
console.log(fn("hello").fn1("world").fn1("!!!").fn());
I think this should do the trick:
function fn(s){
return new function(){
this.str = s;
this.fn = (ns) => {if(ns){this.str += " "+ns; return this;} else return this.str;};
}
}
let a = fn("hello").fn("world").fn("!!!").fn();
console.log(a);
Seems like you need to use objects
const generic = {
"fn1":null,
"current":"",
"fn": () => {
//what do you want to do with "this.current"?
}
}
function fn(str) {
var ret = generic;
ret.fn1 = (wa) =>{
var again = generic;
again.current +=wa;
return again;
}
ret.current += str;
return ret;
}
You can return an object with a .fn() method which will
check if an argument is passed in or not to determine when to terminate the chain or continue chaining.
When no argument is sent, then it simply returns the accumulated string.
Otherwise, it calls fn() function again to accumulate to the string and get the next copy of the same structure as before:
const result = fn("hello").fn("world").fn("!!!").fn();
console.log(result);
function fn (str){
return {
fn(nextString) {
if (nextString === undefined)
return str;
return fn(`${str} ${nextString}`);
}
};
}
Since this operation is immutable, it means each link in the chain is independent, therefore it is no problem with assigning to variables to continue with different chains:
const helloWorld = fn("hello").fn("world");
const one = helloWorld.fn("one").fn();
const two = helloWorld.fn("two").fn();
const three = helloWorld.fn("three").fn();
console.log(one);
console.log(two);
console.log(three);
function fn (str){
return {
fn(nextString) {
if (nextString === undefined)
return str;
return fn(`${str} ${nextString}`);
}
};
}
I have the following app function that stores data. Users can add new items and it returns the length of the data array.
I am trying to understand why returning the data in a function returns the data including the pushed items, but returning the data.length does not and neither does applying a filter. If I request the data length outside of the app function scope, it does return it including the pushed items.
In my example, getfn , app.data.length and app.data.filter returns the added items, but getcntfn and filterinitialfn does not. Why is this?
var app = (function () {
var data = ["initial"];
function add(x) { data.push(x) }
function getfn() { return data };
function getcntfn() { return data.length };
function filterinitialfn(filter) { return data.filter(x => x == filter) }
return {
add: function (x) { add(x) },
data:data,
getfn: getfn(),
getcntfn: getcntfn(),
filterinitialfn: function(filter) {filterinitialfn(filter)}
}
}());
app.add("added")
console.log("app.getfn", app.getfn) //["initial", "added"]
console.log("app.getcntfn", app.getcntfn) //1 ???
console.log("app.data.length", app.data.length) //2
console.log("app.filterinitialfn", app.filterinitialfn("added")) //[] ???
console.log("app.filterinitial=>", app.data.filter(x => x == "added")) //["added"]
because you are calling the function immediately when returning it so it can't be changed from the initial state, so change it to:
return {
add: function (x) { add(x) },
data:data,
getfn: getfn,
getcntfn: getcntfn,
filterinitialfn: filterinitialfn,
}
of course, when using then you should include parentheses.
For example, the result of getfn: getfn() is evaluated when being initialised, it wont' change the value when calling it.
You'll need to pass the function itself, without calling it so it's evaluated on the call:
getfn: getfn,
getcntfn: getcntfn,
...
Since all your functions have the same name as the return object key, we can use the shorthand to create the object:
var app = (function () {
var data = ["initial"];
function add(x) { data.push(x) }
function getfn() { return data };
function getcntfn() { return data.length };
function filterinitialfn(filterBy) { return data.filter(x => x == "added") }
function filterBy(filterBy) { return data.filter(x => x == filterBy); }
return {
add,
data,
getfn,
getcntfn,
filterinitialfn,
filterBy
}
}());
app.add("added")
console.log("app.getfn", app.getfn())
console.log("app.getcntfn", app.getcntfn())
console.log("app.data.length", app.data.length)
console.log("app.filterinitialfn", app.filterinitialfn())
console.log("app.filterinitial=>", app.data.filter(x => x == "added"))
console.log("app.filterBy", app.filterBy('initial'))
I know we can get all arguments in javascript inside function when it is called anywhere . we can get extra arguments which we didnt asked also .
But can we get only asked arguments on javascript function?
Like :
function a(a,b){
console.log(arguments);
}
if we call function a somewhere a(1,2,3,4,5)
then the output will be like [1,2,3,4,5]
but i want only [1,2] as i have expected only two params in function?
My condition is
index: (req, res, next) => {
var params = ['batch_id', 'section_id', 'subject_id', 'term', 'assesment_id', 'assesment_type'];
var _ = req._;
req.utils.requestValidation([req,res,next], params,'query')
// But i dont want to send params like above always instead like below
req.utils.requestValidation(arguments, params,'query')
and where it is called is
requestValidation: (data, options, param) => {
if (!options) return;
var _ = data[0]._ || data._;
var rules = {};
var data = {};
var sanity = {};
var elr = [validator.escape, validator.ltrim, validator.rtrim];
options.map((item, index) => {
rules[item] = 'required';
sanity[item] = elr;
});
data[param] = sanity;
if (typeof data != 'string') {
sanitizer.setOptions(data);
var data = sanitizer.sanitize(data[0], data[1], data[2],param);
return data[0].validation.validate(rules, data[0][param]);
}
return data.validation.validate(rules, data[param]);
},
if you need only two parameters just cut arguments to two items
if you want automatic this you can write function-wrapper, something like this:
function wrapperCutParams(func, paramsCount){
return function(){
var args = Array.prototype.slice(arguments, 0);
if(args.length > paramsCount){
args = args.slice(0, paramsCount)
}
func.apply(this, args)
}
}
Then
var a = function a(a,b){
console.log(arguments);
}
a = wrapperCutParams(a, 2)
Or just
a = wrapperCutParams(function a(a,b){
console.log(arguments);
}, 2)
Since you declared those arguments the most readable way would be to use them as they are, if you need to put them in an array, just do it.
myArgs = [a, b];
Write a higher-order function which takes the underlying function as a parameter, and returns a function which truncates the argument list to the number of arguments the function is asking for, based on its length property.
function slice_args(fn) {
return function() {
return fn.apply(this, Array.prototype.slice.call(arguments, 0, fn.length));
};
}
Then
function a(a,b){
console.log(arguments);
}
var b = slice_args(a);
b(1,2,3,4,5)
> [1, 2]
I have a project which requires me to replicate underscore.js's 'reject' function using the 'filter' function. I've written the following, though can't seem to get the tests to pass. Any suggestions?
// Return all elements of an array that pass a truth test.
_.filter = function(collection, test) {
var passed = [];
_.each(collection, function(item, index) {
if (test(item) === true) {
passed.push(item);
}
});
return passed;
};
// Return all elements of an array that don't pass a truth test.
_.reject = function(collection, test) {
_.filter(collection, function(item) {
return !test(item);
});
};
You forgot to return the result of filter.
_.reject = function(collection, test) {
return _.filter(collection, function(item) {
return !test(item);
});
};
I'm working on a project that will do a lot of processing of numbers in arrays. To try and encapsulate some condition logic I've done something like
//ignore the fact that it's a bad idea to extend JS base types
Array.prototype.ifThenElse = function (statement, funcA, funcB, args) {
return (statement) ? funcA(args) : funcB(args);
};
So this takes a boolean expression and executes the funcA if the bool is true, and executes funcB if it is not. The kicker here is that args should be the array itself. So here's a fiddle and the code:
var newData = [1, 2, 3, 4];
Array.prototype.ifThenElse = function (statement, funcA, funcB, args) {
return (statement) ? funcA(args) : funcB(args);
};
function timesTwo(arr) {
return arr.map(function (val, ix) {
return val * 2;
});
};
function timesThree(arr) {
return arr.map(function (val, ix) {
return val * 3;
});
};
var nArray = newData.ifThenElse(newData[0] < newData[1],timesTwo,timesThree,newData);
//console.log('This is the nArray ' + nArray);
var expression = !!0 > 100;
var expression2 = !!100 > 0;
var dData = newData.ifThenElse(expression, timesThree, timesTwo, newData);
var eData = newData.ifThenElse(expression2, timesThree, timesTwo, newData);
console.log(dData);//2,4,6,8 <=expression is false, timesTwo called
console.log(eData);//3,6,9,12 <=expression is true, timesThree called
I don't want to hardcode the functions that can be passed to `ifThenElse, but I'd also looking to see if there's a clever solution to make this more LINQ-like and somehow have newData automatically passed as the last parameter of the method
The value of this in a method called from an object generally refers to the object on which it was called.
Because your Array.prototype method is called on an Array, the value of this in the method is a reference to the Array.
So just pass this to pass the Array.
return (statement) ? funcA(this) : funcB(this);