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);
Related
I have written a javascript object 'myMath' as follows:
But in the 'mean' function, callback is not being called.
const myMath = {
square(x){
return x**2;
},
mean(array, callback){
if(callback){
array.map(callback);
}
const total = array.reduce((acc,x)=>acc+x);
return total/array.length;
}
};
When tried to invoke the function as follows output obtained is 2, and not 4.6666..., which is expected.
myMath.mean([1,2,3],x=>x**2);
<< 2
Why is it so ? And How can I resolve that ?
.map returns a new array. It's that one you need to work with after the map operation.
const myMath = {
square(x){
return x**2;
},
mean(array, callback){
let mapped = callback ? array.map(callback) : array;
const total = mapped.reduce((acc,x)=>acc+x);
return total/mapped.length;
}
};
console.log(myMath.mean([1,2,3],x=>x**2));
console.log(myMath.mean([1,2,3]));
Array.map is not "mutating" method, so you should save mapped value:
array = array.map(callback);
So I'm working on updating some old projects and I am trying to find a source or an example of something I'm trying to accomplish.
what I have
// sample object of functions
var functions = {
required : function(value){
return value.length > 0;
},
isObject : function(value){
return typeof value == 'object';
}
};
Above is a sample of functions in an object. What I want to know is can the following be done:
pseudo code
//user input
var funcs = [required(''), isObject({key : 'v'})];
// what the function I'm building will process, in a sense
functions[funcs[i]](//arguments from funcs[i]);
// what would remain after each function
funcs = [false, true] // with an end result of false
I'm not 100% sure that this can't be done, I'm just not sure how in the slightest something like this would be able to come about. Let's bounce some ideas around here and see what we come up with.
Let me know if you all need any clarification of anything I asked. Thank you ahead of time for all help!
clarification on what I am trying to achieve
The object of functions is not finite, there can be any amount of functions for this specific program I am writing. They are going to be predefined, so user input is not going to be an issue. I need to be able to determine what function is called when it is passed, and make sure any arguments passed with said function are present and passed as well. So when I pass required(''), I need to be able to go through my object of functions and find functions['required'] and passed the empty string value with it. So like this functions['required']('').
other issues
The functions object is private access and the user won't have direct access to it.
How about this.
var functions = {
required : function(value){
return value.length > 0;
},
isObject : function(value){
return typeof value == 'object';
}
};
// Because these values are user inputs, they should be strings,
// so I enclosed them in quotes.
var funcs = ["required('')", "isObject({key: 'v'})"];
funcs.map(function(e) {
return eval('functions.' + e);
});
Running this should gives you an array of return values from the functions in the object.
Trivially, this could be done with:
var tests = [functions.required(''), functions.isObject({key: 'v'})];
If that's all you need, consider that my answer.
For a more general approach, the right tool here seems to be Arrays.prototype.map(). However, since you have an object containing all your functions instead of an array of functions, you'll need some way to make the correspondence. You can easily do this with a separate array of property names (e.g., ['required', 'isObject']). Then you could do something like this:
var functions = {
required : function(value){
return value.length > 0;
},
isObject : function(value){
return typeof value == 'object';
}
};
var args = ['', {key: 'v'}];
var results = ['required', 'isObject'].map(
function(test, i) {
return functions[test](args[i]);
}
);
Of course, if functions were an array instead of an object, you could simplify this:
var functions = [
/* required : */ function(value){
return value.length > 0;
},
/* isObject : */ function(value){
return typeof value == 'object';
}
];
var args = ['', {key: 'v'}];
var results = functions.map(
function(test, i) {
return test(args[i]);
}
);
If you wanted to encapsulate this a bit, you could pass the args array as a second argument to map(), in which case inside the function you would use this[i] instead of args[i].
Sure it's possible. Something like this:
var results = [];
var value = "value_to_pass_in";
for(var f in functions)
{
results.push(f.call(this, value));
}
UPDATE:
function superFunc(value)
{
var results = [];
for(var f in functions)
{
results.push(f.call(this, value));
}
return results;
}
superFunc("value_to_pass_in");
What you want is a map function. You can mimic it like this (I guess if you want one line):
https://jsfiddle.net/khoorooslary/88gh2yeh/
var inOneLine = (function() {
var resp = {};
var i = 0;
var fns = {
required : function(value){
return value.length > 0;
},
isObject : function(value){
return typeof value == 'object';
}
};
for (var k in fns) resp[k] = fns[k](arguments[i++]);
return resp;
}).apply(null, [ '' , {key : 'v'}]);
console.log(inOneLine);
var functions = {
required : function(value){
return value.length > 0;
},
isObject : function(value){
return typeof value == 'object';
}
};
var funcs = ["required('')", "isObject({key: 'v'})"];
function f(funcs){
return funcs.map(function(e) {
return eval('functions.' + e);
});
}
console.log(f(funcs));
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]
//find value in array using function checkValue using underscoreJS _.each.
//return true, else false.
var helloArr = ['bonjour', 'hello', 'hola'];
var checkValue = function(arg) {
_.each(helloArr, function(helloArr, index) {
if (arg[index] === index) {
return true;
}
return false;
});
};
alert(checkValue("hola"));
The problem with your code is that, _.each will iterate through all the elements of the array and call the function you pass to it. You will not be able to come to a conclusion with that, since you are not getting any value returned from it (unless you maintain state outside _.each).
Note that the values returned from the function you pass to _.each will not be used anywhere and they will not affect the course of the program in any way.
But, instead, you can use _.some as an alternate, like this
var checkValue = function(arg) {
return _.some(helloArr, function(currentString) {
return arg === currentString;
});
};
But, a better solution would be, _.contains function for this purpose. You can use it like this
var checkValue = function(arg) {
return _.contains(helloArr, arg);
};
But, since you have only Strings in the Array, the best solution would be to use Array.prototype.indexOf, like this
var checkValue = function(arg) {
return helloArr.indexOf(arg) !== -1;
};
Try this:
var helloArr = ['bonjour', 'hello', 'hola'];
var checkValue = function(arr, val) {
_(arr).each(function(value) {
if (value == val)
{return console.log(true);}
else {return console.log(false);}
});
};
console.log(checkValue(helloArr,'hello'));
/* Output
false
true
false*/
Is there anyway to prototype or extend the native Function object in JavaScript to run another function on function calls ?
Function.prototype.called = function() {
var start = new Date().getTime();
var returnValue = this();
this.end = new Date().getTime() - start;
this.calls += 1;
return returnValue;
};
Of course this code doesn't work but the goal here would be to benchmark function call execution times.
I know that I could do this outside the function itself and by not extending the native Function object (which is generally a bad idea) but this is really only an experiment rather than a serious solution.
I want to benchmark multiple functions so this would be a less tedious solution.
It is also the reason why I don't prototype the call and apply properties (which would mean that I would have to rewrite every function call test() into test.call()).
Thank you in advance !
It is not possible to efficiently intercept all method calls in JavaScript. You can always override Function.prototype.call and Function.prototype.apply, but these aren't called when calling a function normally, e.g. someFunction();.
However, if you are targetting methods from specific objects, you could always do a deep-traversal of these objects and wrap every function into an interceptor function. However, be advised that you would have to rerun that interception process for every method added after the process ran.
I created an example for you:
/**
* AOP utility function developed for learning purposes.
*
* #param {Object} o The object to traverse for overriding functions.
* #param {RegExp} rx A regular expression for matching members.
* #param {String} pointcut 'before' or 'after'.
* #param {Function} advice The function to run when the pointcut is met. This function will be passed an {Options} object as last argument.
* #param {maxDepth} maxDepth The maximum depth for deep-traversal. Defaults to 0.
*
* Options object
* overrideReturn {Boolean} - True to override the return value of the original function with the return value of the advice. Defaults to false. Pointcuts: before, after
* cancel {Boolean} - True to avoid calling the original function. Default to false. Pointcuts: before
* overrideArgs {Boolean} - True to override the arguments that will be passed to the original function with the result of the advice. Defaults to false. Pointcuts: before
* result {*} - The return value of the original function. Pointcuts: after
*/
function inject(o, rx, pointcut, advice, maxDepth) {
var pointcuts = {
before: function (fn1, fn2) {
return function () {
var options = injectNewOptions(arguments, BeforeOptions),
fn2Result = fn2.apply(this, arguments),
fn1Result;
if (options.cancel) {
return fn2Result;
}
fn1Result = fn1.apply(this, (options.overrideArgs ? fn2Result : arguments));
return options.overrideReturn ? fn2Result : fn1Result;
};
},
after: function (fn1, fn2) {
return function () {
var fn1Result = fn1.apply(this, arguments),
options = injectNewOptions(arguments, Options),
fn2Result;
options.result = fn1Result;
fn2Result = fn2.apply(this, arguments);
return options.overrideReturn ? fn2Result : fn1Result;
};
}
},
Options = {
overrideReturn: false
},
BeforeOptions = Object.create(Options, {
cancel: {
enumerable: true,
writable: true,
value: false
},
overrideArgs: {
enumerable: true,
writable: true,
value: false
}
});
function injectNewOptions(args, baseOptions) {
var options = Object.create(baseOptions);
Array.prototype.push.call(args, options);
return options;
}
inject = function (o, rx, pointcut, advice, maxDepth, depth) {
var k, f;
maxDepth = maxDepth || 0;
depth = 0 || depth;
for (k in o) {
if (typeof (f = o[k]) === 'function' && rx.test(k)) {
o[k] = pointcuts[pointcut](f, advice, pointcut);
} else if (typeof f === 'object' && maxDepth <= depth) {
inject(f, rx, pointcut, advice, maxDepth, ++depth);
}
}
};
inject.apply(this, arguments);
}
Now we can use inject like:
var o = {
sum: function (a, b) {
return a + b;
},
product: function (a, b) {
return a * b;
}
};
inject(o, /^sum$/, 'before', function () {
var options = arguments[arguments.length - 1]; //get options object
//override the arguments passed to the intercepted method
options.overrideArgs = true;
return [2, 2];
});
inject(o, /^product$/, 'after', function () {
var options = arguments[arguments.length - 1]; //get options object
//override the arguments passed to the intercepted method
options.overrideReturn = true;
return options.result + 3;
});
o.sum(1, 2); //4 because we have overriden the args with [2, 2]
o.product(2, 2); //7 because we added 3 to the result and overrided the return value
EDIT:
It's worth mentionning here what #Bergi said in the comments.
If you want to profile all functions instead of just a few selected
ones, you're better off using your browser's developer tools instead
of some script.