Calling dynamic function with dynamic number of parameters [duplicate] - javascript

This question already has answers here:
Passing an array as a function parameter in JavaScript
(12 answers)
Passing arguments forward to another javascript function
(5 answers)
Closed 6 years ago.
I’m looking for a trick about this. I know how to call a dynamic, arbitrary function in JavaScript, passing specific parameters, something like this:
function mainfunc(func, par1, par2){
window[func](par1, par2);
}
function calledfunc(par1, par2){
// Do stuff here
}
mainfunc('calledfunc', 'hello', 'bye');
I know how to pass optional, unlimited parameters using the arguments collection inside mainfunc, but, I can’t figure how to send an arbitrary number of parameters to mainfunc to be sent to calledfunc dynamically; how can I accomplish something like this, but with any number of optional arguments (not using that ugly if–else)?
function mainfunc(func){
if(arguments.length == 3)
window[func](arguments[1], arguments[2]);
else if(arguments.length == 4)
window[func](arguments[1], arguments[2], arguments[3]);
else if(arguments.length == 5)
window[func](arguments[1], arguments[2], arguments[3], arguments[4]);
}
function calledfunc1(par1, par2){
// Do stuff here
}
function calledfunc2(par1, par2, par3){
// Do stuff here
}
mainfunc('calledfunc1', 'hello', 'bye');
mainfunc('calledfunc2', 'hello', 'bye', 'goodbye');

Use the apply method of a function:-
function mainfunc (func){
window[func].apply(null, Array.prototype.slice.call(arguments, 1));
}
Edit: It occurs to me that this would be much more useful with a slight tweak:-
function mainfunc (func){
this[func].apply(this, Array.prototype.slice.call(arguments, 1));
}
This will work outside of the browser (this defaults to the global space). The use of call on mainfunc would also work:-
function target(a) {
alert(a)
}
var o = {
suffix: " World",
target: function(s) { alert(s + this.suffix); }
};
mainfunc("target", "Hello");
mainfunc.call(o, "target", "Hello");

Your code only works for global functions, ie. members of the window object. To use it with arbitrary functions, pass the function itself instead of its name as a string:
function dispatch(fn, args) {
fn = (typeof fn == "function") ? fn : window[fn]; // Allow fn to be a function object or the name of a global function
return fn.apply(this, args || []); // args is optional, use an empty array by default
}
function f1() {}
function f2() {
var f = function() {};
dispatch(f, [1, 2, 3]);
}
dispatch(f1, ["foobar"]);
dispatch("f1", ["foobar"]);
f2(); // calls inner-function "f" in "f2"
dispatch("f", [1, 2, 3]); // doesn't work since "f" is local in "f2"

You could use .apply()
You need to specify a this... I guess you could use the this within mainfunc.
function mainfunc (func)
{
var args = new Array();
for (var i = 1; i < arguments.length; i++)
args.push(arguments[i]);
window[func].apply(this, args);
}

Here's what you need:
function mainfunc (){
window[Array.prototype.shift.call(arguments)].apply(null, arguments);
}
The first argument is used as the function name and all of the remaining ones are used as arguments to the called function...
We're able to use the shift method to return and then delete the first value from the arguments array. Note that we've called it from the Array prototype since, strictly speaking, 'arguments' is not a real array and so doesn't inherit the shift method like a regular array would.
You can also call the shift method like this:
[].shift.call(arguments);

The simplest way might be:
var func='myDynamicFunction_'+myHandler;
var arg1 = 100, arg2 = 'abc';
window[func].apply(null,[arg1, arg2]);
Assuming, that target function is already attached to a "window" object.

If you want to pass with "arguments" a few others, you have to create the array of all arguments together, i.e. like this:
var Log = {
log: function() {
var args = ['myarg here'];
for(i=0; i<arguments.length; i++) args = args.concat(arguments[i]);
console.log.apply(this, args);
}
}

Now I'm using this:
Dialoglar.Confirm = function (_title, _question, callback_OK) {
var confirmArguments = arguments;
bootbox.dialog({
title: "<b>" + _title + "</b>",
message: _question,
buttons: {
success: {
label: "OK",
className: "btn-success",
callback: function () {
if (typeof(callback_OK) == "function") { callback_OK.apply(this,Array.prototype.slice.call(confirmArguments, 3));
}
}
},
danger: {
label: "Cancel",
className: "btn-danger",
callback: function () {
$(this).hide();
}
}
}
});
};

function a(a, b) {
return a + b
};
function call_a() {
return a.apply(a, Array.prototype.slice.call(arguments, 0));
}
console.log(call_a(1, 2))
console: 3

Couldn't you just pass the arguments array along?
function mainfunc (func){
// remove the first argument containing the function name
arguments.shift();
window[func].apply(null, arguments);
}
function calledfunc1(args){
// Do stuff here
}
function calledfunc2(args){
// Do stuff here
}
mainfunc('calledfunc1','hello','bye');
mainfunc('calledfunc2','hello','bye','goodbye');

In case somebody is still looking for dynamic function call with dynamic parameters -
callFunction("aaa('hello', 'world')");
function callFunction(func) {
try
{
eval(func);
}
catch (e)
{ }
}
function aaa(a, b) {
alert(a + ' ' + b);
}

Related

Calling multiple functions with names matching Regex

I have some functions like these:
function name_a(){}
function name_b(){}
function name_x(){}
function name_n(){}
I want to call all functions start with name_ with regex in javascript.
How can I do that?
Just for the kicks, here's something you can use. ES5, so IE>9 is required (could be tweaked for older browsers support, though).
/**
* Calls functions of given target object with names matching given regex.
*
* #param {any} targetObject
* #param {RegExp} nameRegex
* #param {...any} functionsArguments
*
* #returns {any[]} The values returned by each function called.
*/
function callFunctionsMatching(targetObject, nameRegex, functionsArguments) {
// make arguments into array, then splice
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
var functionsArgs = (arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments)).splice(2);
return Object.getOwnPropertyNames(targetObject).filter(function (propertyName) {
return typeof targetObject[propertyName] == 'function' && nameRegex.test(propertyName);
}).map(function (functionName) {
return targetObject[functionName].apply(targetObject, functionsArgs);
});
}
Usage (demo JSBin here)
Global functions (window target object):
// setup some functions
function a1(a, b, c, d) { console.log('a1->', a, b, c, d); }
function b1(arg) { console.log('b1->', arg); }
window.c1 = console.log
// call every function ending with 1
callFunctionsMatching(window, /1$/, 'stuff', 1, 3, 4);
Output:
a1-> stuff 1 3 4
b1-> stuff
stuff 1 3 4
Objects functions (any object as target):
var person = {
aa: function(x) { console.log('person.aa called with', x); return 'this is the return value of person.aa'; },
aaz: function(x) { console.log('I shouldn have been printed'); }
};
var valuesReturned = callFunctionsMatching(person, /aa$/, 'some argument');
console.log('valuesReturned were', valuesReturned);
Output:
person.aa called with some argument
valuesReturned were ["this is the return value of person.aa"]
Example from the question:
function name_a(){ console.log('name_a called'); }
function name_b(){ console.log('name_b called'); }
function name_x(){ console.log('name_x called'); }
function name_n(){ console.log('name_n called'); }
callFunctionsMatching(window, /^name_/, 'args');
Output:
function name_a called
function name_x called
function name_n called
function name_b called
This doesn't handle DOM objects, but if you have a plain object and simply want to search for all the functions matching a certain regex at one level, you could (optionally, showing executing each one in order):
function get_func_filter(obj, match) {
var keys = Object.getOwnPropertyNames(obj);
return keys.filter(function(func_name) {
return typeof obj[func_name] === 'function'
&& match.test(func_name);
});
}
var funcs = {
'prop_a': 'value',
'prop_b': 'value',
'name_a': function(){console.log('name_a function called');},
'name_b': function(){console.log('name_b function called');},
'name_c': function(){console.log('name_c function called');},
'not_name_a': function(){console.log('not_name_a function called');},
'not_name_b': function(){console.log('not_name_b function called');},
};
// First, get the function names that match "starting with name_"
get_func_filter(funcs, /^name_/)
// Then get each name
.map(function(func_name) {
// And execute it (the second)
!funcs[func_name] || funcs[func_name]();
}
);
https://jsfiddle.net/5vrfpmeq/

How to dynamically change a function

I have a function that has already been assigned and I would like to append some additional script. When I display the function like:
var func = obj.when_clicked;
alert(func);
The following is displayed:
function object_123(){
object_123_Action();
}
The type is a "function" and the function is executed elsewhere which I cannot change, the code is:
this.when_clicked();
I need to modify the function by appending my own code so it becomes:
function object_123(){
object_123_Action();
my_clicked(obj);
}
Then add that back and over write the when_clicked function.
It does work if I manually add the code like:
obj.when_clicked = function object_123(){object_123_Action();my_clicked(obj);};
However, I do not know what is in the function initially, all I want is to append the:
my_clicked(obj);
I do need the obj to be the actual object of interest which is obj.
You can wrap it:
var f = this.when_clicked;
this.when_clicked = function() {
// Call the original
var rv = f.apply(this, arguments);
// your code here
// Return the original function's return value
return rv;
};
Function#apply calls the original with the specified this flag. arguments is provided by the JavaScript engine: It's a pseudo-array of the arguments your function was called with, so the above just passes all of them on.
Be sure to think about what it means if your function throws an exception, and catch them if you want to suppress them.
If you do this often, you can giev yourself a utility function:
function wrapFunction(f, wrapper) {
return function() {
var rv = f.apply(this, arguments);
wrapper.apply(this, arguments);
return rv;
};
}
Then
this.when_clicked = wrapFunction(this.when_clicked, function() {
// Your code here
});
Or if you want access to the original's return value, potentially changing it:
function wrapFunction(f, wrapper) {
return function() {
var rv = f.apply(this, arguments);
rv = wrapper.call(this, rv, arguments);
return rv;
};
}
Then
this.when_clicked = wrapFunction(this.when_clicked, function(rv, args) {
// Your code here, using `rv` and `args`, which is a pseudo-array
// Potentially update `rv`
return rv;
});
You can store your functions in an array on the object.
Then, loop though the functions in another function and execute them.
var myObj = { 'myfunctions': [ ] };
and to add functions:
myObj.myFunctions.push (function () { /*function code here*/ });
Or if you already have a named function:
myObj.myFunctions.push (nameOfFunction);
And to call all the functions, use this function (don't add this function to myObj)
function executeMyFunctions (myObj) {
for (var i = 0; i < myObj.myFunctions.length; i++) {
myObj.myFunctions[i]();
}
}
Used this answer on another question of #peter. Meant to post here.

How to overload functions in javascript?

Classical (non-js) approach to overloading:
function myFunc(){
//code
}
function myFunc(overloaded){
//other code
}
Javascript wont let more than one function be defined with the same name. As such, things like this show up:
function myFunc(options){
if(options["overloaded"]){
//code
}
}
Is there a better workaround for function overloading in javascript other than passing an object with the overloads in it?
Passing in overloads can quickly cause a function to become too verbose because each possible overload would then need a conditional statement. Using functions to accomplish the //code inside of those conditional statements can cause tricky situations with scopes.
There are multiple aspects to argument overloading in Javascript:
Variable arguments - You can pass different sets of arguments (in both type and quantity) and the function will behave in a way that matches the arguments passed to it.
Default arguments - You can define a default value for an argument if it is not passed.
Named arguments - Argument order becomes irrelevant and you just name which arguments you want to pass to the function.
Below is a section on each of these categories of argument handling.
Variable Arguments
Because javascript has no type checking on arguments or required qty of arguments, you can just have one implementation of myFunc() that can adapt to what arguments were passed to it by checking the type, presence or quantity of arguments.
jQuery does this all the time. You can make some of the arguments optional or you can branch in your function depending upon what arguments are passed to it.
In implementing these types of overloads, you have several different techniques you can use:
You can check for the presence of any given argument by checking to see if the declared argument name value is undefined.
You can check the total quantity or arguments with arguments.length.
You can check the type of any given argument.
For variable numbers of arguments, you can use the arguments pseudo-array to access any given argument with arguments[i].
Here are some examples:
Let's look at jQuery's obj.data() method. It supports four different forms of usage:
obj.data("key");
obj.data("key", value);
obj.data();
obj.data(object);
Each one triggers a different behavior and, without using this dynamic form of overloading, would require four separate functions.
Here's how one can discern between all these options in English and then I'll combine them all in code:
// get the data element associated with a particular key value
obj.data("key");
If the first argument passed to .data() is a string and the second argument is undefined, then the caller must be using this form.
// set the value associated with a particular key
obj.data("key", value);
If the second argument is not undefined, then set the value of a particular key.
// get all keys/values
obj.data();
If no arguments are passed, then return all keys/values in a returned object.
// set all keys/values from the passed in object
obj.data(object);
If the type of the first argument is a plain object, then set all keys/values from that object.
Here's how you could combine all of those in one set of javascript logic:
// method declaration for .data()
data: function(key, value) {
if (arguments.length === 0) {
// .data()
// no args passed, return all keys/values in an object
} else if (typeof key === "string") {
// first arg is a string, look at type of second arg
if (typeof value !== "undefined") {
// .data("key", value)
// set the value for a particular key
} else {
// .data("key")
// retrieve a value for a key
}
} else if (typeof key === "object") {
// .data(object)
// set all key/value pairs from this object
} else {
// unsupported arguments passed
}
},
The key to this technique is to make sure that all forms of arguments you want to accept are uniquely identifiable and there is never any confusion about which form the caller is using. This generally requires ordering the arguments appropriately and making sure that there is enough uniqueness in the type and position of the arguments that you can always tell which form is being used.
For example, if you have a function that takes three string arguments:
obj.query("firstArg", "secondArg", "thirdArg");
You can easily make the third argument optional and you can easily detect that condition, but you cannot make only the second argument optional because you can't tell which of these the caller means to be passing because there is no way to identify if the second argument is meant to be the second argument or the second argument was omitted so what's in the second argument's spot is actually the third argument:
obj.query("firstArg", "secondArg");
obj.query("firstArg", "thirdArg");
Since all three arguments are the same type, you can't tell the difference between different arguments so you don't know what the caller intended. With this calling style, only the third argument can be optional. If you wanted to omit the second argument, it would have to be passed as null (or some other detectable value) instead and your code would detect that:
obj.query("firstArg", null, "thirdArg");
Here's a jQuery example of optional arguments. both arguments are optional and take on default values if not passed:
clone: function( dataAndEvents, deepDataAndEvents ) {
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
return this.map( function () {
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
});
},
Here's a jQuery example where the argument can be missing or any one of three different types which gives you four different overloads:
html: function( value ) {
if ( value === undefined ) {
return this[0] && this[0].nodeType === 1 ?
this[0].innerHTML.replace(rinlinejQuery, "") :
null;
// See if we can take a shortcut and just use innerHTML
} else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
value = value.replace(rxhtmlTag, "<$1></$2>");
try {
for ( var i = 0, l = this.length; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
if ( this[i].nodeType === 1 ) {
jQuery.cleanData( this[i].getElementsByTagName("*") );
this[i].innerHTML = value;
}
}
// If using innerHTML throws an exception, use the fallback method
} catch(e) {
this.empty().append( value );
}
} else if ( jQuery.isFunction( value ) ) {
this.each(function(i){
var self = jQuery( this );
self.html( value.call(this, i, self.html()) );
});
} else {
this.empty().append( value );
}
return this;
},
Named Arguments
Other languages (like Python) allow one to pass named arguments as a means of passing only some arguments and making the arguments independent of the order they are passed in. Javascript does not directly support the feature of named arguments. A design pattern that is commonly used in its place is to pass a map of properties/values. This can be done by passing an object with properties and values or in ES6 and above, you could actually pass a Map object itself.
Here's a simple ES5 example:
jQuery's $.ajax() accepts a form of usage where you just pass it a single parameter which is a regular Javascript object with properties and values. Which properties you pass it determine which arguments/options are being passed to the ajax call. Some may be required, many are optional. Since they are properties on an object, there is no specific order. In fact, there are more than 30 different properties that can be passed on that object, only one (the url) is required.
Here's an example:
$.ajax({url: "http://www.example.com/somepath", data: myArgs, dataType: "json"}).then(function(result) {
// process result here
});
Inside of the $.ajax() implementation, it can then just interrogate which properties were passed on the incoming object and use those as named arguments. This can be done either with for (prop in obj) or by getting all the properties into an array with Object.keys(obj) and then iterating that array.
This technique is used very commonly in Javascript when there are large numbers of arguments and/or many arguments are optional. Note: this puts an onus on the implementating function to make sure that a minimal valid set of arguments is present and to give the caller some debug feedback what is missing if insufficient arguments are passed (probably by throwing an exception with a helpful error message).
In an ES6 environment, it is possible to use destructuring to create default properties/values for the above passed object. This is discussed in more detail in this reference article.
Here's one example from that article:
function selectEntries({ start=0, end=-1, step=1 } = {}) {
···
};
Then, you can call this like any of these:
selectEntries({start: 5});
selectEntries({start: 5, end: 10});
selectEntries({start: 5, end: 10, step: 2});
selectEntries({step: 3});
selectEntries();
The arguments you do not list in the function call will pick up their default values from the function declaration.
This creates default properties and values for the start, end and step properties on an object passed to the selectEntries() function.
Default values for function arguments
In ES6, Javascript adds built-in language support for default values for arguments.
For example:
function multiply(a, b = 1) {
return a*b;
}
multiply(5); // 5
Further description of the ways this can be used here on MDN.
Overloading a function in JavaScript can be done in many ways. All of them involve a single master function that either performs all the processes, or delegates to sub-functions/processes.
One of the most common simple techniques involves a simple switch:
function foo(a, b) {
switch (arguments.length) {
case 0:
//do basic code
break;
case 1:
//do code with `a`
break;
case 2:
default:
//do code with `a` & `b`
break;
}
}
A more elegant technique would be to use an array (or object if you're not making overloads for every argument count):
fooArr = [
function () {
},
function (a) {
},
function (a,b) {
}
];
function foo(a, b) {
return fooArr[arguments.length](a, b);
}
That previous example isn't very elegant, anyone could modify fooArr, and it would fail if someone passes in more than 2 arguments to foo, so a better form would be to use a module pattern and a few checks:
var foo = (function () {
var fns;
fns = [
function () {
},
function (a) {
},
function (a, b) {
}
];
function foo(a, b) {
var fnIndex;
fnIndex = arguments.length;
if (fnIndex > foo.length) {
fnIndex = foo.length;
}
return fns[fnIndex].call(this, a, b);
}
return foo;
}());
Of course your overloads might want to use a dynamic number of parameters, so you could use an object for the fns collection.
var foo = (function () {
var fns;
fns = {};
fns[0] = function () {
};
fns[1] = function (a) {
};
fns[2] = function (a, b) {
};
fns.params = function (a, b /*, params */) {
};
function foo(a, b) {
var fnIndex;
fnIndex = arguments.length;
if (fnIndex > foo.length) {
fnIndex = 'params';
}
return fns[fnIndex].apply(this, Array.prototype.slice.call(arguments));
}
return foo;
}());
My personal preference tends to be the switch, although it does bulk up the master function. A common example of where I'd use this technique would be a accessor/mutator method:
function Foo() {} //constructor
Foo.prototype = {
bar: function (val) {
switch (arguments.length) {
case 0:
return this._bar;
case 1:
this._bar = val;
return this;
}
}
}
You cannot do method overloading in strict sense. Not like the way it is supported in java or c#.
The issue is that JavaScript does NOT natively support method overloading. So, if it sees/parses two or more functions with a same names it’ll just consider the last defined function and overwrite the previous ones.
One of the way I think is suitable for most of the case is follows -
Lets say you have method
function foo(x)
{
}
Instead of overloading method which is not possible in javascript you can define a new method
fooNew(x,y,z)
{
}
and then modify the 1st function as follows -
function foo(x)
{
if(arguments.length==2)
{
return fooNew(arguments[0], arguments[1]);
}
}
If you have many such overloaded method consider using switch than just if-else statements.
(more details)
PS: Above link goes to my personal blog that has additional details on this.
I am using a bit different overloading approach based on arguments number.
However i believe John Fawcett's approach is also good.
Here the example, code based on John Resig's (jQuery's Author) explanations.
// o = existing object, n = function name, f = function.
function overload(o, n, f){
var old = o[n];
o[n] = function(){
if(f.length == arguments.length){
return f.apply(this, arguments);
}
else if(typeof o == 'function'){
return old.apply(this, arguments);
}
};
}
usability:
var obj = {};
overload(obj, 'function_name', function(){ /* what we will do if no args passed? */});
overload(obj, 'function_name', function(first){ /* what we will do if 1 arg passed? */});
overload(obj, 'function_name', function(first, second){ /* what we will do if 2 args passed? */});
overload(obj, 'function_name', function(first,second,third){ /* what we will do if 3 args passed? */});
//... etc :)
I tried to develop an elegant solution to this problem described here. And you can find the demo here. The usage looks like this:
var out = def({
'int': function(a) {
alert('Here is int '+a);
},
'float': function(a) {
alert('Here is float '+a);
},
'string': function(a) {
alert('Here is string '+a);
},
'int,string': function(a, b) {
alert('Here is an int '+a+' and a string '+b);
},
'default': function(obj) {
alert('Here is some other value '+ obj);
}
});
out('ten');
out(1);
out(2, 'robot');
out(2.5);
out(true);
The methods used to achieve this:
var def = function(functions, parent) {
return function() {
var types = [];
var args = [];
eachArg(arguments, function(i, elem) {
args.push(elem);
types.push(whatis(elem));
});
if(functions.hasOwnProperty(types.join())) {
return functions[types.join()].apply(parent, args);
} else {
if (typeof functions === 'function')
return functions.apply(parent, args);
if (functions.hasOwnProperty('default'))
return functions['default'].apply(parent, args);
}
};
};
var eachArg = function(args, fn) {
var i = 0;
while (args.hasOwnProperty(i)) {
if(fn !== undefined)
fn(i, args[i]);
i++;
}
return i-1;
};
var whatis = function(val) {
if(val === undefined)
return 'undefined';
if(val === null)
return 'null';
var type = typeof val;
if(type === 'object') {
if(val.hasOwnProperty('length') && val.hasOwnProperty('push'))
return 'array';
if(val.hasOwnProperty('getDate') && val.hasOwnProperty('toLocaleTimeString'))
return 'date';
if(val.hasOwnProperty('toExponential'))
type = 'number';
if(val.hasOwnProperty('substring') && val.hasOwnProperty('length'))
return 'string';
}
if(type === 'number') {
if(val.toString().indexOf('.') > 0)
return 'float';
else
return 'int';
}
return type;
};
In javascript you can implement the function just once and invoke the function without the parameters myFunc() You then check to see if options is 'undefined'
function myFunc(options){
if(typeof options != 'undefined'){
//code
}
}
https://github.com/jrf0110/leFunc
var getItems = leFunc({
"string": function(id){
// Do something
},
"string,object": function(id, options){
// Do something else
},
"string,object,function": function(id, options, callback){
// Do something different
callback();
},
"object,string,function": function(options, message, callback){
// Do something ca-raaaaazzzy
callback();
}
});
getItems("123abc"); // Calls the first function - "string"
getItems("123abc", {poop: true}); // Calls the second function - "string,object"
getItems("123abc", {butt: true}, function(){}); // Calls the third function - "string,object,function"
getItems({butt: true}, "What what?" function(){}); // Calls the fourth function - "object,string,function"
No Problem with Overloading in JS , The pb how to maintain a clean code when overloading function ?
You can use a forward to have clean code, based on two things:
Number of arguments (when calling the function).
Type of arguments (when calling the function)
function myFunc(){
return window['myFunc_'+arguments.length+Array.from(arguments).map((arg)=>typeof arg).join('_')](...arguments);
}
/** one argument & this argument is string */
function myFunc_1_string(){
}
//------------
/** one argument & this argument is object */
function myFunc_1_object(){
}
//----------
/** two arguments & those arguments are both string */
function myFunc_2_string_string(){
}
//--------
/** Three arguments & those arguments are : id(number),name(string), callback(function) */
function myFunc_3_number_string_function(){
let args=arguments;
new Person(args[0],args[1]).onReady(args[3]);
}
//--- And so on ....
How about using a proxy (ES6 Feature)?
I didn't find anywhere mentioning this method of doing it. It might be impractical but it's an interesting way nonetheless.
It's similar to Lua's metatables, where you can "overload" the call operator with the __call metamethod in order to achieve overloading.
In JS, it can be done with the apply method in a Proxy handler. You can check the arguments' existence, types, etc. inside the said method, without having to do it in the actual function.
MDN: proxy apply method
function overloads() {}
overloads.overload1 = (a, b) => {
return a + b;
}
overloads.overload2 = (a, b, c) => {
return a + b + c;
}
const overloadedFn = new Proxy(overloads, { // the first arg needs to be an Call-able object
apply(target, thisArg, args) {
if (args[2]) {
return target.overload2(...args);
}
return target.overload1(...args);
}
})
console.log(overloadedFn(1, 2, 3)); // 6
console.log(overloadedFn(1, 2)); // 3
Check this out:
http://www.codeproject.com/Articles/688869/Overloading-JavaScript-Functions
Basically in your class, you number your functions that you want to be overloaded and then with one function call you add function overloading, fast and easy.
Since JavaScript doesn't have function overload options object can be used instead. If there are one or two required arguments, it's better to keep them separate from the options object. Here is an example on how to use options object and populated values to default value in case if value was not passed in options object.
function optionsObjectTest(x, y, opts) {
opts = opts || {}; // default to an empty options object
var stringValue = opts.stringValue || "string default value";
var boolValue = !!opts.boolValue; // coerces value to boolean with a double negation pattern
var numericValue = opts.numericValue === undefined ? 123 : opts.numericValue;
return "{x:" + x + ", y:" + y + ", stringValue:'" + stringValue + "', boolValue:" + boolValue + ", numericValue:" + numericValue + "}";
}
here is an example on how to use options object
For this you need to create a function that adds the function to an object, then it will execute depending on the amount of arguments you send to the function:
<script >
//Main function to add the methods
function addMethod(object, name, fn) {
var old = object[name];
object[name] = function(){
if (fn.length == arguments.length)
return fn.apply(this, arguments)
else if (typeof old == 'function')
return old.apply(this, arguments);
};
}
 var ninjas = {
values: ["Dean Edwards", "Sam Stephenson", "Alex Russell"]
};
//Here we declare the first function with no arguments passed
addMethod(ninjas, "find", function(){
return this.values;
});
//Second function with one argument
addMethod(ninjas, "find", function(name){
var ret = [];
for (var i = 0; i < this.values.length; i++)
if (this.values[i].indexOf(name) == 0)
ret.push(this.values[i]);
return ret;
});
//Third function with two arguments
addMethod(ninjas, "find", function(first, last){
var ret = [];
for (var i = 0; i < this.values.length; i++)
if (this.values[i] == (first + " " + last))
ret.push(this.values[i]);
return ret;
});
//Now you can do:
ninjas.find();
ninjas.find("Sam");
ninjas.find("Dean", "Edwards")
</script>
How about using spread operator as a parameter? The same block can be called with Multiple parameters. All the parameters are added into an array and inside the method you can loop in based on the length.
function mName(...opt){
console.log(opt);
}
mName(1,2,3,4); //[1,2,3,4]
mName(1,2,3); //[1,2,3]
I like to add sub functions within a parent function to achieve the ability to differentiate between argument groups for the same functionality.
var doSomething = function() {
var foo;
var bar;
};
doSomething.withArgSet1 = function(arg0, arg1) {
var obj = new doSomething();
// do something the first way
return obj;
};
doSomething.withArgSet2 = function(arg2, arg3) {
var obj = new doSomething();
// do something the second way
return obj;
};
What you are trying to achieve is best done using the function's local arguments variable.
function foo() {
if (arguments.length === 0) {
//do something
}
if (arguments.length === 1) {
//do something else
}
}
foo(); //do something
foo('one'); //do something else
You can find a better explanation of how this works here.
(() => {
//array that store functions
var Funcs = []
/**
* #param {function} f overload function
* #param {string} fname overload function name
* #param {parameters} vtypes function parameters type descriptor (number,string,object....etc
*/
overloadFunction = function(f, fname, ...vtypes) {
var k,l, n = false;
if (!Funcs.hasOwnProperty(fname)) Funcs[fname] = [];
Funcs[fname].push([f, vtypes?vtypes: 0 ]);
window[fname] = function() {
for (k = 0; k < Funcs[fname].length; k++)
if (arguments.length == Funcs[fname][k][0].length) {
n=true;
if (Funcs[fname][k][1]!=0)
for(i=0;i<arguments.length;i++)
{
if(typeof arguments[i]!=Funcs[fname][k][1][i])
{
n=false;
}
}
if(n) return Funcs[fname][k][0].apply(this, arguments);
}
}
}
})();
//First sum function definition with parameter type descriptors
overloadFunction(function(a,b){return a+b},"sum","number","number")
//Second sum function definition with parameter with parameter type descriptors
overloadFunction(function(a,b){return a+" "+b},"sum","string","string")
//Third sum function definition (not need parameter type descriptors,because no other functions with the same number of parameters
overloadFunction(function(a,b,c){return a+b+c},"sum")
//call first function
console.log(sum(4,2));//return 6
//call second function
console.log(sum("4","2"));//return "4 2"
//call third function
console.log(sum(3,2,5));//return 10
//ETC...

Functional JavaScript: how to implement Function.prototype.not

I was working on some code earlier today, when I realized, "Hey! This code would be more concise and semantic if I abstracted the idea of a boolean not out of an anonymous function and into a prototype function..."
Consider a predicate generator:
function equalTo(n) {
return function(x) {
return n==x;
};
}
So you can use it like so:
[1,2,3,4,1,2,3,4].filter(equalTo(2)) == [2,2]
Now, my idea is to make a predicate "inverser":
Function.prototype.not = function() {
//???
}
So that you can say:
[1,2,3,4,1,2,3,4].filter(equalTo(2).not) == [1,3,4,1,3,4]
My first stab at the implementation was probably very naive:
Function.prototype.not = function () {
return ! this(arguments);
}
And probably why it didn't work.
How would you implement this function, and why?
I'm just trying to wrap my head around functional ideas, and know JavaScript well enough to know it can be used to do this, but just not how.
Your implementation won't work for several reasons:
You need to return a function, not a boolean.
You should pass the arguments as-is, not wrapped in an array.
You should preserve the context (this keyword) that the function would have been called in.
I would implement it like this:
Function.prototype.not = function (context) {
var func = this;
return function() { return !func.apply(context || this, arguments); };
}
I return an anonymous function (function() { ... })
I call apply to call the original function in the current contexts with the actual arguments.
(EDIT) Free bonus: I added an optional context parameter which will override this for the callback.
I would probably do it like so (but perhaps with some sort of namespacing):
function not (x) {
return !x;
}
function id (x) {
return x;
}
function compose (/*funcs*/) {
var args = arguments.length
? Array.prototype.slice.call (arguments)
: [id]
;
return function () {
var val = args [args.length - 1].apply (null, arguments);
for (var i = args.length - 2; i >= 0; --i) {
val = args [i] (val);
}
return val;
};
}
[1,2,3,4,1,2,3,4].filter (compose (not, equalTo (2)));
Using your idea:
function equalTo(n) {
var fn = function(x) {
return n == x;
};
fn.not = function(x) {
return n != x; // use this for simpler conditions
return !fn.apply(this, arguments); // use this for more complex logic
}
return fn;
}
So your example would work:
[1,2,3,4,1,2,3,4].filter(equalTo(2).not) == [1,3,4,1,3,4]
Edit: You can write a helper function (better name to be found) so not doesn't need to be redefined every time:
function generateFnWithNot(fn) {
return function () {
var f = fn.apply(this, arguments);
f.not = function () {
return !f.apply(this, arguments);
}
return f;
};
}
So when you're defining your functions, you can define them as normal with the exception of wrapping a generateFnWithNot call:
var equalTo = generateFnWithNot(function (n) {
return function (x) {
return n == x;
};
});
equalTo(5) // resolves to function () { return n == 5; }
equalTo(5).not // resolves to function () { return n != 5; }

How do I wrap a function in Javascript?

I'm writing a global error handling "module" for one of my applications.
One of the features I want to have is to be able to easily wrap a function with a try{} catch{} block, so that all calls to that function will automatically have the error handling code that'll call my global logging method. (To avoid polluting the code everywhere with try/catch blocks).
This is, however, slightly beyond my understanding of the low-level functioning of JavaScript, the .call and .apply methods, and the this keyword.
I wrote this code, based on Prototype's Function.wrap method:
Object.extend(Function.prototype, {
TryCatchWrap: function() {
var __method = this;
return function() {
try { __method.apply(this, arguments) } catch(ex) { ErrorHandler.Exception(ex); }
}
}
});
Which is used like this:
function DoSomething(a, b, c, d) {
document.write(a + b + c)
alert(1/e);
}
var fn2 = DoSomething.TryCatchWrap();
fn2(1, 2, 3, 4);
That code works perfectly. It prints out 6, and then calls my global error handler.
My question is: will this break something when the function I'm wrapping is within an object, and it uses the "this" operator? I'm slightly worried since I'm calling .apply, passing something there, I'm afraid this may break something.
Personally instead of polluting builtin objects I would go with a decorator technique:
var makeSafe = function(fn){
return function(){
try{
return fn.apply(this, arguments);
}catch(ex){
ErrorHandler.Exception(ex);
}
};
};
You can use it like that:
function fnOriginal(a){
console.log(1/a);
};
var fn2 = makeSafe(fnOriginal);
fn2(1);
fn2(0);
fn2("abracadabra!");
var obj = {
method1: function(x){ /* do something */ },
method2: function(x){ /* do something */ }
};
obj.safeMethod1 = makeSafe(obj.method1);
obj.method1(42); // the original method
obj.safeMethod1(42); // the "safe" method
// let's override a method completely
obj.method2 = makeSafe(obj.method2);
But if you do feel like modifying prototypes, you can write it like that:
Function.prototype.TryCatchWrap = function(){
var fn = this; // because we call it on the function itself
// let's copy the rest from makeSafe()
return function(){
try{
return fn.apply(this, arguments);
}catch(ex){
ErrorHandler.Exception(ex);
}
};
};
Obvious improvement will be to parameterize makeSafe() so you can specify what function to call in the catch block.
2017 answer: just use ES6. Given the following demo function:
function doThing(){
console.log(...arguments)
}
You can make your own wrapper function without needing external libraries:
function wrap(someFunction){
function wrappedFunction(){
var newArguments = [...arguments]
newArguments.push('SECRET EXTRA ARG ADDED BY WRAPPER!')
console.log(`You're about to run a function with these arguments: \n ${newArguments}`)
return someFunction(...newArguments)
}
return wrappedFunction
}
In use:
doThing('one', 'two', 'three')
Works as normal.
But using the new wrapped function:
const wrappedDoThing = wrap(doThing)
wrappedDoThing('one', 'two', 'three')
Returns:
one two three SECRET EXTRA ARG ADDED BY WRAPPER!
2016 answer: use the wrap module:
In the example below I'm wrapping process.exit(), but this works happily with any other function (including browser JS too).
var wrap = require('lodash.wrap');
var log = console.log.bind(console)
var RESTART_FLUSH_DELAY = 3 * 1000
process.exit = wrap(process.exit, function(originalFunction) {
log('Waiting', RESTART_FLUSH_DELAY, 'for buffers to flush before restarting')
setTimeout(originalFunction, RESTART_FLUSH_DELAY)
});
process.exit(1);
Object.extend(Function.prototype, {
Object.extend in the Google Chrome Console gives me 'undefined'
Well here's some working example:
Boolean.prototype.XOR =
// ^- Note that it's a captial 'B' and so
// you'll work on the Class and not the >b<oolean object
function( bool2 ) {
var bool1 = this.valueOf();
// 'this' refers to the actual object - and not to 'XOR'
return (bool1 == true && bool2 == false)
|| (bool1 == false && bool2 == true);
}
alert ( "true.XOR( false ) => " true.XOR( false ) );
so instead of
Object.extend(Function.prototype, {...})
Do it like:
Function.prototype.extend = {}
Function wrapping in good old fashion:
//Our function
function myFunction() {
//For example we do this:
document.getElementById('demo').innerHTML = Date();
return;
}
//Our wrapper - middleware
function wrapper(fn) {
try {
return function(){
console.info('We add something else', Date());
return fn();
}
}
catch (error) {
console.info('The error: ', error);
}
}
//We use wrapper - middleware
myFunction = wrapper(myFunction);
The same in ES6 style:
//Our function
let myFunction = () => {
//For example we do this:
document.getElementById('demo').innerHTML = Date();
return;
}
//Our wrapper - middleware
const wrapper = func => {
try {
return () => {
console.info('We add something else', Date());
return func();
}
}
catch (error) {
console.info('The error: ', error);
}
}
//We use wrapper - middleware
myFunction = wrapper(myFunction);
Here is an ES6 style:
const fnOriginal = (a, b, c, d) => {
console.log(a);
console.log(b);
console.log(c);
console.log(d);
return 'Return value from fnOriginal';
};
const wrapperFunction = fn => {
return function () {
try {
const returnValuFromOriginal = fn.apply(this, arguments);
console.log('Adding a new line from Wrapper :', returnValuFromOriginal);
} catch (ex) {
ErrorHandler.Exception(ex);
}
};
};
const fnWrapped = wrapperFunction(fnOriginal);
fnWrapped(1, 2, 3, 4);
The following wrapping utility takes a function and enables the developer to inject a code or wrap the original:
function wrap(originalFunction, { inject, wrapper } = {}) {
const wrapperFn = function(...args) {
if (typeof inject === 'function') {
inject(originalFunction, this);
}
if (typeof wrapper === 'function') {
return wrapper(originalFunction, this, args);
}
return originalFunction.apply(this, args);
};
// copy the original function's props onto the wrapper
for(const prop in originalFunction) {
if (originalFunction.hasOwnProperty(prop)) {
wrapperFn[prop] = originalFunction[prop];
}
}
return wrapperFn;
}
Usage example:
// create window.a()
(function() {
const txt = 'correctly'; // outer scope variable
window.a = function a(someText) { // our target
if (someText === "isn't") {
throw('omg');
}
return ['a', someText, window.a.c, txt].join(' ');
};
window.a.c = 'called'; // a.c property example
})();
const originalFunc = window.a;
console.log(originalFunc('is')); // logs "a is called correctly"
window.a = wrap(originalFunc);
console.log(a('is')); // logs "a is called correctly"
window.a = wrap(originalFunc, { inject(func, thisArg) { console.log('injected function'); }});
console.log(a('is')); // logs "injected function\na is called correctly"
window.a = wrap(originalFunc, { wrapper(func, thisArg, args) { console.log(`doing something else instead of ${func.name}(${args.join(', ')})`); }});
console.log(a('is')); // logs "doing something else instead of a(is)"
window.a = wrap(originalFunc, {
wrapper(func, thisArg, args) {
try {
return func.apply(thisArg, args);
} catch(err) {
console.error('got an exception');
}
}
});
a("isn't"); // error message: "got an exception"
The last example demonstrates how to wrap your function with a try-catch clause
As far as polluting the namespaces, I'm actually going to pollute them some more...
Since everything that happens in JS is initiated by an event of some kind, I'm planning to call my magical wrapper function from within the Prototype Event.observe() method, so I don't need to call it everywhere.
I do see the downsides of all this, of course, but this particular project is heavily tied to Prototype anyway, and I do want to have this error handler code be as global as possible, so it's not a big deal.
Thanks for your answer!

Categories

Resources