JavaScript (NodeJS) equivalent for PHP's call_user_func_array() - javascript

Is there any equivalent function in JavaScript (NodeJS) similar to PHP's
call_user_func_array (http://php.net/manual/en/function.call-user-func-array.php). Which allows to call a function with array of parameters.
In my case, I have to call util.format with parameters that will be in an array.
Here is very simple example trying to show it.
var util = require("util");
function my_fundtion(items) {
var format_string = "";
for (var i=0; i < items.length; i++) {
format_string += " %s";
}
return util.format(format_string, /* here I want to pass items in items array */);
}

PHP has:
call_user_func_array('myfunc', array(1, 2, "foo", false));
While JS has:
myfunc.apply(null, [1, 2, "foo", false]);
The first null goes in the position of an object. You will make use of that if the function is intended to be a method. An example on using such invocation would be to slice array-like objects which are not arrays at all but seem like one (like the arguments object inside of a function):
Array.prototype.slice.apply(arguments, []);
Generally speaking, the syntax is:
(afunction).apply(obj|null, array of arguments)
You can try this:
function my_fundtion(items) {
var format_string = "";
for (var i=0; i < items.length; i++) {
format_string += " %s";
}
var new_items = items.slice();
new_items.unshift(format_string);
return util.format.apply(null, new_items);
}
IMHO that's the wrong approach for a function. Have you tried the following?
function my_fundtion(items) {
return items.join(" ");
}

Because call_user_func_array call function referenced by the function name which is in string. So, in JS we need to use eval.
Example:
const popup = (msg) => {
alert(msg);
}
const subject = {
popup(msg) {
alert(msg);
}
}
So,
eval("popup").apply(null, ['hi'])
eval("subject.popup").apply(null, ['hi'])
Correct me. If i wrong. ;)

Related

How to create a "function that returns a function and splits csv file"? [duplicate]

This question already has answers here:
How do JavaScript closures work?
(86 answers)
Closed 8 years ago.
I'm learning JS and I need help with the following task:
I need to create a function compile_csv_search(text, key_name) that parses text in
the CSV format. (not required to handle quoting and escaping in values;
assume field values never contain commas or other special characters.)
A function must return a function that looks up a record by a value of the
field specified as the second argument to compile_csv_search. Assume that all
values in the key field are unique.
Sample usage:
var csv_by_name = compile_csv_search(
"ip,name,desc\n"+
"1.94.0.2,server1,Main Server\n"+
"1.53.8.1,server2,Backup Server\n",
"name");
console.log(csv_by_name("server2"));
console.log(csv_by_name("server9"));
...will print:
{ip: "10.52.5.1", name: "server2", desc: "Backup Server"}
undefined
** I didn't understand what does it mean "function that return function". How can function return another function?
Thank you!
P.S.
attaching my solution for your review
function compile_csv_search(csvServerData){
var header = csvServerData.split('\n')[0].split(",");
var spleatedServerData = csvServerData.split('\n');
return function(serverName)
{
for(var i = 1; i < spleatedServerData.length; i++){
var singleServer = spleatedServerData[i].split(',')
var result = {};
var exist = false;
for (var j = 0; j < header.length; j++) {
if(singleServer.indexOf(serverName) == -1)
break;
exist = true;
result[header[j]] = singleServer[j];
}
if(exist){
return(result);
break;
}
}
}
}
var csv_by_name = compile_csv_search(
"ip,name,desc\n"+
"10.49.1.4,server1,Main Server\n"+
"10.52.5.1,server2,Backup Server\n");
Functions in JavaScript are objects; they can be referred to by variables, passed as arguments and returned from functions like any other object.
Here's a function that returns an object:
function returnObject() {
var result = { a: 1, b: 2, c: 3 };
return result;
}
And here's a function that returns another function:
function returnFunction() {
var result = function() {
console.log('another function!');
}
return result;
}
Notice how they're really similar - object returned by the first function is a plain Object created using object literal syntax ({}), and the object returned by the second happens to be a function.
You could call the inner, returned function like this:
var out = returnFunction();
out();
Or even returnFunction()();
However, you can't just call result() - result is only defined inside of returnFunction. The only way to access it from outside is to retrieve it by calling the outer function.
Something like this would be fine:
function compile_csv_search(text, key_name) {
var lines = text.split('\n');
var keys = lines[0].split(',');
var key_index = keys.indexOf(key_name);
return function(value) {
for(var i = 1; i<lines.length; i++) {
current_line_values = lines[i].split(',');
if(current_line_values[key_index] === value) {
var result = {};
for(var j = 0; j<keys.length; j++) {
result[keys[j]] = current_line_values[j];
}
return result;
}
}
}
}
Also see this fiddle: http://jsfiddle.net/efha0drq/
You can always treat a function the same as any other js objects. Assign to a variable, pass to a function, store in an array... all are fine.
The magic in this example is that, you can read/write the variables defined in the compile_csv_search() function within the returned function. So it's possible to store something in the local variables of the defining function, and later retrieve from the returned one, even when the defining function has finished execution long time ago. You may have heard of "closure", right?

How to convert javascript array to function

I have an array of arbitrary values. I Wrote a function that transforms the array to an array of functions that return the original values, so instead of calling a[3], I will call a3.
Here is my code which does not work? code. It gives this error Cannot call method '1' of undefined.
var numToFun = [1, 2, { foo: "bar" }];
var numToFunLength = numToFun.length;
function transform(numTo) {
for (var i = 0; i < numToFunLength; i++) {
(function(num){
numTo.unshift(function() {
return num;
});
}(numTo.pop()))
}
}
var b = transform(numToFun);
console.log(numToFun);
console.log(b[1]());​
Others have already answered your question while I was writing mine but I will post it anyway - this may be somewhat easier to follow without all of those popping and unshifting:
function transform(numTo) {
var r = [];
for (var i = 0; i < numTo.length; i++) {
r[i] = (function (v) {
return function() {
return v;
}
}(numTo[i]));
}
return r;
}
(I have also changed the hard-coded length from numToFunLength to numTo.length so the transform() function would work for other inputs than only the global numToFun variable.)
See DEMO.
UPDATE: even more elegant way to do it using the Sugar library:
function transform(array) {
return array.map(function (v) {
return function() {
return v;
}
});
}
I like this syntax because it makes it more explicit that you want to map an array of values to an array of functions that return those values.
See DEMO.
Your function transform does not return anything. That is why b is undefined.
return numTo;
jsFiddle Demo
On the other hand, the array will be passed to the function as a reference anyways, so the original array will be changed. It is not a problem if you don't return anything, just omit the var b = transform(numToFun); line and simply write transform(numToFun).
Your transform function isn't returning anything. So b is undefined

Best use of the arguments property in JavaScript?

What's the right way to use the arguments property of a function?
This is how I'm currently using it, but I'm pretty sure I'm not using it correctly:
First, I define my parameters:
parameters = {};
parameters.ID = $tr.data('ID');
parameters.Name = 'Name goes here';
parameters.td = $td;
UpdateName(parameters);
And in the function:
var UpdateName = function(){
var local = {};
local.ID = arguments[0].ID;
local.Name = arguments[0].Name;
local.td = arguments[0].td;
local.jqXHR = $.ajax('Remote/Ajax.cfc', {
data: {
method:'UpdateName'
,returnformat:'json'
,ID:local.ID
,Name:local.Name
}
});
local.jqXHR.success(function(result){
if (result.MSG == '') {
local.td.text(local.Name).addClass('success');
} else {
local.td.addClass('err');
};
});
local.jqXHR.error(function(result){
local.td.addClass('err');
});
}
The arguments object is most useful for functions that accept an arbitrary/unknown number of arguments. The MDC gives this example for creating HTML lists of any length:
function list(type) {
var result = "<" + type + "l>";
// iterate through non-type arguments
for (var i = 1; i < arguments.length; i++)
result += "<li>" + arguments[i] + "</li>";
result += "</" + type + "l>"; // end list
return result;
}
...which can be used like this:
var listHTML = list("u", "One", "Two", "Three");
// listHTML is "<ul><li>One</li><li>Two</li><li>Three</li></ul>"
Because of arguments, we can pass any number of items to list and it just works. (Notice that even in this case the known parameter, type, is named and iteration of arguments begins on its second element.)
Your list of parameters is well-defined, so there's no reason not to simply name the parameters in your function declaration. Using arguments as you are is unnecessary and harder to read.
You technically are using it correctly, but I don't see the practical point in your code though. The arguments variable contains a array-like object of the arguments passed to a function. E.g.
function test() {
alert(arguments[0]);
alert(arguments[1]);
}
test("Hello", 123); // alerts Hello and 123
In your example, instead of an object, you can pass the properties as arguments and retrieve them from arguments.
JavaScript functions are capable of using named arguments.
In your case, this could simplify your code as follows:
var UpdateName = function(local) {
$.ajax('Remote/Ajax.cfc', {
data: {
method:'UpdateName',
returnformat:'json',
ID:local.ID,
Name:local.Name,
success: function(result) {
if (result.MSG == '') {
local.td.text(local.Name).addClass('success');
} else {
local.td.addClass('err');
}
},
error: function(result) {
local.td.addClass('err');
}
}
});
}
I modified the code so that you don't need to keep a reference to jqXHR anymore since you aren't doing anything with it anyway. I also moved the leading commas to the end of each line, but that is just a preference.

Javascript Array of Functions

var array_of_functions = [
first_function('a string'),
second_function('a string'),
third_function('a string'),
forth_function('a string')
]
array_of_functions[0];
That does not work as intended because each function in the array is executed when the array is created.
What is the proper way of executing any function in the array by doing:
array_of_functions[0]; // or, array_of_functions[1] etc.
Thanks!
var array_of_functions = [
first_function,
second_function,
third_function,
forth_function
]
and then when you want to execute a given function in the array:
array_of_functions[0]('a string');
I think this is what the original poster meant to accomplish:
var array_of_functions = [
function() { first_function('a string') },
function() { second_function('a string') },
function() { third_function('a string') },
function() { fourth_function('a string') }
]
for (i = 0; i < array_of_functions.length; i++) {
array_of_functions[i]();
}
Hopefully this will help others (like me 20 minutes ago :-) looking for any hint about how to call JS functions in an array.
Without more detail of what you are trying to accomplish, we are kinda guessing. But you might be able to get away with using object notation to do something like this...
var myFuncs = {
firstFunc: function(string) {
// do something
},
secondFunc: function(string) {
// do something
},
thirdFunc: function(string) {
// do something
}
}
and to call one of them...
myFuncs.firstFunc('a string')
I would complement this thread by posting an easier way to execute various functions within an Array using the shift() Javascript method originally described here
var a = function(){ console.log("this is function: a") }
var b = function(){ console.log("this is function: b") }
var c = function(){ console.log("this is function: c") }
var foo = [a,b,c];
while (foo.length){
foo.shift().call();
}
Or just:
var myFuncs = {
firstFun: function(string) {
// do something
},
secondFunc: function(string) {
// do something
},
thirdFunc: function(string) {
// do something
}
}
It's basically the same as Darin Dimitrov's but it shows how you could use it do dynamically create and store functions and arguments.
I hope it's useful for you :)
var argsContainer = ['hello', 'you', 'there'];
var functionsContainer = [];
for (var i = 0; i < argsContainer.length; i++) {
var currentArg = argsContainer[i];
functionsContainer.push(function(currentArg){
console.log(currentArg);
});
};
for (var i = 0; i < functionsContainer.length; i++) {
functionsContainer[i](argsContainer[i]);
}
up above we saw some with iteration. Let's do the same thing using forEach:
var funcs = [function () {
console.log(1)
},
function () {
console.log(2)
}
];
funcs.forEach(function (func) {
func(); // outputs 1, then 2
});
//for (i = 0; i < funcs.length; i++) funcs[i]();
Ah man there are so many weird answers...
const execute = (fn) => fn()
const arrayOfFunctions = [fn1, fn2, fn3]
const results = arrayOfFunctions.map(execute)
or if you want to sequentially feed each functions result to the next:
compose(fn3, fn2, fn1)
compose is not supported by default, but there are libraries like ramda, lodash, or even redux which provide this tool
This is correct
var array_of_functions = {
"all": function(flag) {
console.log(1+flag);
},
"cic": function(flag) {
console.log(13+flag);
}
};
array_of_functions.all(27);
array_of_functions.cic(7);
If you're doing something like trying to dynamically pass callbacks you could pass a single object as an argument. This gives you much greater control over which functions you want to you execute with any parameter.
function func_one(arg) {
console.log(arg)
};
function func_two(arg) {
console.log(arg+' make this different')
};
var obj = {
callbacks: [func_one, func_two],
params: ["something", "something else"];
};
function doSomething(obj) {
var n = obj.counter
for (n; n < (obj.callbacks.length - obj.len); n++) {
obj.callbacks[n](obj.params[n]);
}
};
obj.counter = 0;
obj.len = 0;
doSomething(obj);
//something
//something else make this different
obj.counter = 1;
obj.len = 0;
doSomething(obj);
//something else make this different
Execution of many functions through an ES6 callback 🤗
const f = (funs) => {
funs().forEach((fun) => fun)
}
f(() => [
console.log(1),
console.log(2),
console.log(3)
])
Using ES6 syntax, if you need a "pipeline" like process where you pass the same object through a series of functions (in my case, a HTML abstract syntax tree), you can use for...of to call each pipe function in a given array:
const setMainElement = require("./set-main-element.js")
const cacheImages = require("./cache-images.js")
const removeElements = require("./remove-elements.js")
let htmlAst = {}
const pipeline = [
setMainElement,
cacheImages,
removeElements,
(htmlAst) => {
// Using a dynamic closure.
},
]
for (const pipe of pipeline) {
pipe(htmlAst)
}
A short way to run 'em all:
[first_function, ..., nth_function].forEach (function(f) {
f('a string');
});
the probleme of these array of function are not in the "array form" but in the way these functions are called... then...
try this.. with a simple eval()...
array_of_function = ["fx1()","fx2()","fx3()",.."fxN()"]
var zzz=[];
for (var i=0; i<array_of_function.length; i++)
{ var zzz += eval( array_of_function[i] ); }
it work's here, where nothing upper was doing the job at home...
hopes it will help
Using Function.prototype.bind()
var array_of_functions = [
first_function.bind(null,'a string'),
second_function.bind(null,'a string'),
third_function.bind(null,'a string'),
forth_function.bind(null,'a string')
]
I have many problems trying to solve this one... tried the obvious, but did not work. It just append an empty function somehow.
array_of_functions.push(function() { first_function('a string') });
I solved it by using an array of strings, and later with eval:
array_of_functions.push("first_function('a string')");
for (var Func of array_of_functions) {
eval(Func);
}
maybe something like this would do the trick:
[f1,f2,f3].map((f) => f('a string'))
Maybe it can helps to someone.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.manager = {
curHandler: 0,
handlers : []
};
manager.run = function (n) {
this.handlers[this.curHandler](n);
};
manager.changeHandler = function (n) {
if (n >= this.handlers.length || n < 0) {
throw new Error('n must be from 0 to ' + (this.handlers.length - 1), n);
}
this.curHandler = n;
};
var a = function (n) {
console.log("Handler a. Argument value is " + n);
};
var b = function (n) {
console.log("Handler b. Argument value is " + n);
};
var c = function foo(n) {
for (var i=0; i<n; i++) {
console.log(i);
}
};
manager.handlers.push(a);
manager.handlers.push(b);
manager.handlers.push(c);
</script>
</head>
<body>
<input type="button" onclick="window.manager.run(2)" value="Run handler with parameter 2">
<input type="button" onclick="window.manager.run(4)" value="Run handler with parameter 4">
<p>
<div>
<select name="featured" size="1" id="item1">
<option value="0">First handler</option>
<option value="1">Second handler</option>
<option value="2">Third handler</option>
</select>
<input type="button" onclick="manager.changeHandler(document.getElementById('item1').value);" value="Change handler">
</div>
</p>
</body>
</html>
This answered helped me but I got stuck trying to call each function in my array a few times. So for rookies, here is how to make an array of functions and call one or all of them, a couple different ways.
First we make the array.
let functionsArray = [functionOne, functionTwo, functionThree];
We can call a specific function in the array by using its index in the array (remember 0 is the first function in the array).
functionsArray[0]();
We have to put the parenthesis after because otherwise we are just referencing the function, not calling it.
If you wanted to call all the functions we could use a couple different ways.
For loop
for (let index = 0; index < functionsArray.length; index++) {
functionsArray[index]();
}
Don't forget the parenthesis to actually call the function.
ForEach
ForEach is nice because we don't have to worry about the index, we just get handed each element in the array which we can use. We use it like this (non arrow function example below):
functionsArray.forEach(element => {
element();
});
In a ForEach you can rename element in the above to be whatever you want. Renaming it, and not using arrow functions could look like this:
functionsArray.forEach(
function(funFunctionPassedIn) {
funFunctionPassedIn();
}
);
What about Map?
We shouldn't use Map in this case, since map builds a new array, and using map when we aren't using the returned array is an anti-pattern (bad practice).
We shouldn't be using map if we are not using the array it returns, and/or
we are not returning a value from the callback. Source
I know I am late to the party but here is my opinion
let new_array = [
(data)=>{console.log(data)},
(data)=>{console.log(data+1)},
(data)=>{console.log(data+2)}
]
new_array[0]
you got some top answers above. This is just another version of that.
var dictFun = {
FunOne: function(string) {
console.log("first function");
},
FuncTwo: function(string) {
console.log("second function");
},
FuncThree: function(string) {
console.log("third function");
}
}
/* PlanetGreeter */
class PlanetGreeter {
hello : { () : void; } [] = [];
planet_1 : string = "World";
planet_2 : string = "Mars";
planet_3 : string = "Venus";
planet_4 : string = "Uranus";
planet_5 : string = "Pluto";
constructor() {
this.hello.push( () => { this.greet(this.planet_1); } );
this.hello.push( () => { this.greet(this.planet_2); } );
this.hello.push( () => { this.greet(this.planet_3); } );
this.hello.push( () => { this.greet(this.planet_4); } );
this.hello.push( () => { this.greet(this.planet_5); } );
}
greet(a: string) : void { alert("Hello " + a); }
greetRandomPlanet() : void {
this.hello [ Math.floor( 5 * Math.random() ) ] ();
}
}
new PlanetGreeter().greetRandomPlanet();

How can I extend Array.prototype.push()?

I'm trying to extend the Array.push method so that using push will trigger a callback method and then perform the normal array function.
I'm not quite sure how to do this, but here's some code I've been playing with unsuccessfully.
arr = [];
arr.push = function(data){
//callback method goes here
this = Array.push(data);
return this.length;
}
arr.push('test');
Since push allows more than one element to be pushed, I use the arguments variable below to let the real push method have all arguments.
This solution only affects the arr variable:
arr.push = function () {
//Do what you want here...
return Array.prototype.push.apply(this, arguments);
}
This solution affects all arrays. I do not recommend that you do that.
Array.prototype.push = (function() {
var original = Array.prototype.push;
return function() {
//Do what you want here.
return original.apply(this, arguments);
};
})();
First you need subclass Array:
ES6 (https://kangax.github.io/compat-table/es6/):
class SortedArray extends Array {
constructor(...args) {
super(...args);
}
push() {
return super.push(arguments);
}
}
ES5 (proto is almost deprecated, but it is the only solution for now):
function SortedArray() {
var arr = [];
arr.push.apply(arr, arguments);
arr.__proto__ = SortedArray.prototype;
return arr;
}
SortedArray.prototype = Object.create(Array.prototype);
SortedArray.prototype.push = function() {
this.arr.push(arguments);
};
Array.prototype.push was introduced in JavaScript 1.2. It is really as simple as this:
Array.prototype.push = function() {
for( var i = 0, l = arguments.length; i < l; i++ ) this[this.length] = arguments[i];
return this.length;
};
You could always add something in the front of that.
You could do it this way:
arr = []
arr.push = function(data) {
alert(data); //callback
return Array.prototype.push.call(this, data);
}
If you're in a situation without call, you could also go for this solution:
arr.push = function(data) {
alert(data); //callback
//While unlikely, someone may be using "psh" to store something important
//So we save it.
var saved = this.psh;
this.psh = Array.prototype.push;
var ret = this.psh(data);
this.psh = saved;
return ret;
}
While I'm telling you how to do it, you might be better served with using a different method that performs the callback and then just calls push on the array rather than overriding push. You may end up with some unexpected side effects. For instance, push appears to be varadic (takes a variable number of arguments, like printf), and using the above would break that.
You'd need to do mess with _Arguments() and _ArgumentsLength() to properly override this function. I highly suggest against this route.
Or you could use "arguments", and that'd work too. I still advise against taking this route though.
There's another, more native method to achieve this: Proxy
const target = [];
const handler = {
set: function(array, index, value) {
// Call callback function here
// The default behavior to store the value
array[index] = value;
// Indicate success
return true;
}
};
const proxyArray = new Proxy(target, handler);
I wanted to call a function after the object has been pushed to the array, so I did the following:
myArray.push = function() {
Array.prototype.push.apply(this, arguments);
myFunction();
return myArray.length;
};
function myFunction() {
for (var i = 0; i < myArray.length; i++) {
//doSomething;
}
}

Categories

Resources