javascript equivalent of php call_user_func - javascript

I've found this topic which I've implemented (see accepted answer):
javascript equivalent of PHP's call_user_func()
However, I am having a problem with multiple parameters. I realize what I was doing was turning my parameters into strings and treating it like 1 parameter, but I don't know how to fix this because I am dynamically creating the parameters.
Meaning, I have defined in my code the following:
var a = new Array();
a[0] = new Array();
a[0][0] = 'alert';
a[0][1] = '\'Hello World\'';
a[1] = new Array();
a[1][0] = 'setTimeout';
a[1][1] = 'alert("goodbye world")';
a[1][2] = '20';
Later, I was calling them like this:
var j = 0;
var len = 0;
var fx = '';
var params = '';
for( i in a ){
params = '';
len = a[i].length;
fx = a[i][0]; // getting the function name
a[i].splice( 0, 1 ); // removing it from array
if( len > 1 ){
params = a[i].join(", "); // trying to turn the parameters into the right format, but this is turning it into strings I think
params = params.replace(/\\'/g,'\''); // bc i was adding slashes with PHP
}
window[fx](params);
}
I don't have to use arrays to do this. I don't understand JS OOP (haven't tried yet), though I am comfortable with PHP OOP, so I don't know if there is a way to do this there.
Any help on passing multiple parameters would be appreciated.
Thanks.

First thing to do: Scrap your entire code, start over. Your approach will not get you anywhere where you'd want to be. (Unfortunately I can't tell you where you'd want to be because I cannot make sense of your example.)
There are three ways to call a function in JavaScript.
function foo() { console.log(arguments); }
// 1. directly
foo(1, 2, 3);
// 2. trough Function.call()
foo.call(this, 1, 2, 3);
// 3. trough Function.apply()
var args = [1, 2, 3];
foo.apply(this, args);
call and apply are similar. They let you decide which object the this keyword will point to inside the function (that's the important bit!).
apply accepts an array of arguments, call accepts individual arguments.
The closest thing to call() is PHP's call_user_func(). The closest thing to apply() is PHP's call_user_func_array().
JavaScript objects share something with PHP arrays: They are key/value pairs.
// an anonymous function assigned to the key "foo"
var obj = {
foo: function () { console.log(arguments); }
};
This means you can access object properties either with the dot notation:
// direct function call
obj.foo(1, 2, 3);
Or through square bracket notation (note that object keys are strings):
var funcName = "foo";
obj[funcName](1, 2, 3);
obj[funcName].call(obj, 1, 2, 3);
obj[funcName].apply(obj, [1, 2, 3]);
Square bracket notation gives you the freedom to choose an object property dynamically. If this property happens to be a function, apply() gives you the freedom to choose function arguments dynamically.
Every top-level function that has not been declared as the property of some object will become the property of the global object. In browsers the global object is window. (So the function foo() in my first code block above really is window.foo.)
Note that this does not work like in PHP. It will point to the object the function has been called on, not the object the function "belongs to". (The concept "belongs to" does not really exist in JavaScript. Things can be modeled that way, but it's only a convention.)
With direct calling (obj.foo(1, 2, 3)), this will point to obj. With call and apply, this will point to whatever object you want to. This is a lot more useful than it sounds at first. Most of the time when you want to call functions dynamically, you will end up using apply.

Check out Function.apply:
function test(a, b) { console.log([a, b]) }
test.apply(null, [1, 2]); // => [ 1, 2 ]

Late to the party, but now with ES6 you can simply do
function FunctionX(a,b,c,d){
return a + b + c + d;
}
let fx = "FunctionX";
let params = [ 1, 10, 100, 200 ];
let answer = window[fx]( ... params);
let answer2 = globalThis[fx]( ... params ); // this is more cross-platform
to unpack your argument array

Related

How do higher-order functions like `map()` and `reduce()` receive their data?

I'm trying to write my own higher order function right now and I want to know how functions like map() and reduce() access the array they are being applied to. And not just for arrays either, but with any higher order function like toString() or toLowerCase().
array.map()
^^^ // How do I get this data when I am writing my own higher order function?
array.myOwnFunction(/* data??? */)
I hope this makes sense. I'm sure the answer is out there already, but I'm struggling to know what to search for to find the information.
You can add it to the Array prototype like :
Array.prototype.myOwnFunction = function() {
for (var i = 0; i < this.length; i++) {
this[i] += 1;
}
return this;
};
const array = [1, 2, 3];
const result = array.myOwnFunction();
console.log(result);
Check the polyfill for Array.prototype.map(), this line in particular:
// 1. Let O be the result of calling ToObject passing the |this|
// value as the argument.
var O = Object(this);
Simplifying, this is where the values are received.
The way this works is related to the prototype and to the "thisBinding".
When a function is instantiated using new, the properties of the prototype are attached to the new Function object. As well, an "execution context" is created to maintain the environment. The properties of the prototype are then accessible in the environment through the current instance's this binding using this.
So if you have a function you want to use the data from in an instance, you can use a prototype as well. For many reasons (memory use, readability, reusability, inheritance, polymorphism, etc.) this is the best way to go about doing it. Modifying standard implementations such as Array, Math, Date, etc. are generally discouraged (although there will always be exceptions).
function LineItem(description,price,quantity){
this.description = description;
this.price = price;
this.quantity = quantity;
}
LineItem.prototype.Total = function(){
return this.price * this.quantity;
};
var avocados = new LineItem("avocado",2.99,3);
console.log(avocados.Total());
The main thing to take away here is that the thisBinding allows access to the current instance's object through this. That is where the data access comes from. For example, in an array instance, this references the current array; in a date instance, this references the current date; in the above LineItem example, this references the current LineItem.
Thanks to the responses to this question I was able to write a higher order component that accepts a callback function as an argument. Here is the code as an example:
Array.prototype.myFunction = function (callback) {
const items = this
const newArray = []
for (let item of items) {
item = callback(item)
newArray.push(item)
}
return newArray
}
const array = [1, 2, 3, 4]
const result = array.myFunction((item => {
return item + 1
}))
console.log(result)

How is this operation called in JavaScript [duplicate]

As can be seen in the Mozilla changlog for JavaScript 1.7 they have added destructuring assignment. Sadly I'm not very fond of the syntax (why write a and b twice?):
var a, b;
[a, b] = f();
Something like this would have been a lot better:
var [a, b] = f();
That would still be backwards compatible. Python-like destructuring would not be backwards compatible.
Anyway the best solution for JavaScript 1.5 that I have been able to come up with is:
function assign(array, map) {
var o = Object();
var i = 0;
$.each(map, function(e, _) {
o[e] = array[i++];
});
return o;
}
Which works like:
var array = [1,2];
var _ = assign[array, { var1: null, var2: null });
_.var1; // prints 1
_.var2; // prints 2
But this really sucks because _ has no meaning. It's just an empty shell to store the names. But sadly it's needed because JavaScript doesn't have pointers. On the plus side you can assign default values in the case the values are not matched. Also note that this solution doesn't try to slice the array. So you can't do something like {first: 0, rest: 0}. But that could easily be done, if one wanted that behavior.
What is a better solution?
First off, var [a, b] = f() works just fine in JavaScript 1.7 - try it!
Second, you can smooth out the usage syntax slightly using with():
var array = [1,2];
with (assign(array, { var1: null, var2: null }))
{
var1; // == 1
var2; // == 2
}
Of course, this won't allow you to modify the values of existing variables, so IMHO it's a whole lot less useful than the JavaScript 1.7 feature. In code I'm writing now, I just return objects directly and reference their members - I'll wait for the 1.7 features to become more widely available.
You don't need the dummy "_" variable. You can directly create "global" variables by using the window object scope:
window["foo"] = "bar";
alert(foo); // Gives "bar"
Here are few more points:
I wouldn't name this function
"assign" because that's too generic
a term.
To more closely resemble JS
1.7 syntax, I'd make the function take the destination as the first
argument and the source as the
second argument.
Using an object literal to pass the destination variables is cool but can be confused with JS 1.7 destructuring where the destination is actually an object and not an array. I prefer just using a comma delimited list of variable names as a string.
Here's what I came up with:
function destructure(dest, src) {
dest = dest.split(",");
for (var i = 0; i < src.length; i++) {
window[dest[i]] = src[i];
}
}
var arr = [42, 66];
destructure("var1,var2", arr);
alert(var1); // Gives 42
alert(var2); // Gives 66
Here's what I did in PHPstorm 10:
File -> Settings -> Languages & Frameworks -> ...
... set JavaScript language version to e.g. JavaScript 1.8.5...
-> click Apply.
In standard JavaScript we get used to all kinds of ugliness, and emulating destructuring assignment using an intermediate variable is not too bad:
function divMod1(a, b) {
return [ Math.floor(a / b), a % b ];
}
var _ = divMod1(11, 3);
var div = _[0];
var mod = _[1];
alert("(1) div=" + div + ", mod=" + mod );
However I think the following pattern is more idomatic:
function divMod2(a, b, callback) {
callback(Math.floor(a / b), a % b);
}
divMod2(11, 3, function(div, mod) {
alert("(2) div=" + div + ", mod=" + mod );
});
Note, that instead of returning the two results as an array, we pass them as arguments to a callback function.
(See code running at http://jsfiddle.net/vVQE3/ )

Understanding javascript borrowing methods

There is a lot of explanation about how to convert a function's arguments to a real array.
But I have found it very interesting when you simplify the code with the help of bind.
MDN Array.prototype.slice - Array-like objects
MDN Function.prototype.bind - Creating shortcuts
For example:
function list() {
return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
Simplified call:
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);
function list() {
return slice(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
It is working the same way if you use apply instead of call:
var slice = Function.prototype.apply.bind(unboundSlice);
Which can be even shortened by using call from any function instance, since is the same as the one in the prototype and same approach with slice from an array instance:
var slice = alert.call.bind([].slice);
You can try
var slice = alert.call.bind([].slice);
function list() {
console.log(slice(arguments));
}
list(1, 2, 3, 4);
So the first very weird thing is coming into my mind is calling bind on apply, but the first argument of bind should be an object (as context) and not a function (Array.prototype.slice).
The other is that is working with both call and apply the same way.
I am writing javascript for quite a long time and using these methods day to day confidently but I can not wrap my head around this.
Maybe I am missing some very fundamental detail.
Could somebody give an explanation?
the first argument of bind should be an object (as context)
Yes.
and not a function (Array.prototype.slice).
Why not? For one, all functions are objects, so nothing wrong here.
From another perspective, if you use slice.call(…) or slice.apply(…) then the slice object is the context (receiver) of the call/apply method invocations.
What is the difference between binding apply and call?
There is no difference between applyBoundToSlice(arguments) and callBoundToSlice(arguments). The difference is applyBoundToSlice(arguments, [0, n]) vs callBoundToSlice(arguments, 0, n) if you want pass start and end arguments to the slice.
One can use call keyword to implement method borrowing. Below example shows method borrowing.
var john = {
name: "John",
age: 30,
isAdult: function() {
console.log(this.name+"'s age is "+this.age);
if (this.age > 18) {
return true;
} else {
return false;
}
}
}
console.log(john.isAdult());
var rita = {
name: "Rita",
age: 15
}
console.log(john.isAdult.call(rita));
Observe the last line. How the keyword call is used and how rita object is passed to the function.

What is this javascript code doing?

this.String = {
Get : function (val) {
return function() {
return val;
}
}
};
What is the ':' doing?
this.String = {} specifies an object. Get is a property of that object. In javascript, object properties and their values are separated by a colon ':'.
So, per the example, you would call the function like this
this.String.Get('some string');
More examples:
var foo = {
bar : 'foobar',
other : {
a : 'wowza'
}
}
alert(foo.bar); //alerts 'foobar'
alert(foo.other.a) //alerts 'wowza'
Others have already explained what this code does. It creates an object (called this.String) that contains a single function (called Get). I'd like to explain when you could use this function.
This function can be useful in cases where you need a higher order function (that is a function that expects another function as its argument).
Say you have a function that does something to each element of an Array, lets call it map. You could use this function like so:
function inc (x)
{
return x + 1;
}
var arr = [1, 2, 3];
var newArr = arr.map(inc);
What the map function will do, is create a new array containing the values [2, 3, 4]. It will do this by calling the function inc with each element of the array.
Now, if you use this method a lot, you might continuously be calling map with all sorts of arguments:
arr.map(inc); // to increase each element
arr.map(even); // to create a list of booleans (even or odd)
arr.map(toString); // to create a list of strings
If for some reason you'd want to replace the entire array with the same string (but keeping the array of the same size), you could call it like so:
arr.map(this.String.Get("my String"));
This will create a new array of the same size as arr, but just containing the string "my String" over and over again.
Note that in some languages, this function is predefined and called const or constant (since it will always return the same value, each time you call it, no matter what its arguments are).
Now, if you think that this example isn't very useful, I would agree with you. But there are cases, when programming with higher order functions, when this technique is used.
For example, it can be useful if you have a tree you want to 'clear' of its values but keep the structure of the tree. You could do tree.map(this.String.Get("default value")) and get a whole new tree is created that has the exact same shape as the original, but none of its values.
It assigns an object that has a property "Get" to this.String. "Get" is assigned an anonymous function, which will return a function that just returns the argument that was given to the first returning function. Sounds strange, but here is how it can be used:
var ten = this.String["Get"](10)();
ten will then contain a 10. Instead, you could have written the equivalent
var ten = this.String.Get(10)();
// saving the returned function can have more use:
var generatingFunction = this.String.Get("something");
alert(generatingFunction()); // displays "something"
That is, : just assigns some value to a property.
This answer may be a bit superflous since Tom's is a good answer but just to boil it down and be complete:-
this.String = {};
Adds an object to the current object with the property name of String.
var fn = function(val) {
return function() { return(val); }
}
Returns a function from a closure which in turn returns the parameter used in creating the closure. Hence:-
var fnInner = fn("Hello World!");
alert(fnInner()); // Displays Hello World!
In combination then:-
this.String = { Get: function(val) {
return function() { return(val); }
}
Adds an object to the current object with the property name of String that has a method called Get that returns a function from a closure which in turn returns the parameter used in creating the closure.
var fnInner = this.String.Get("Yasso!");
alert(fnInner()); //displays Yasso!

Destructuring assignment in JavaScript

As can be seen in the Mozilla changlog for JavaScript 1.7 they have added destructuring assignment. Sadly I'm not very fond of the syntax (why write a and b twice?):
var a, b;
[a, b] = f();
Something like this would have been a lot better:
var [a, b] = f();
That would still be backwards compatible. Python-like destructuring would not be backwards compatible.
Anyway the best solution for JavaScript 1.5 that I have been able to come up with is:
function assign(array, map) {
var o = Object();
var i = 0;
$.each(map, function(e, _) {
o[e] = array[i++];
});
return o;
}
Which works like:
var array = [1,2];
var _ = assign[array, { var1: null, var2: null });
_.var1; // prints 1
_.var2; // prints 2
But this really sucks because _ has no meaning. It's just an empty shell to store the names. But sadly it's needed because JavaScript doesn't have pointers. On the plus side you can assign default values in the case the values are not matched. Also note that this solution doesn't try to slice the array. So you can't do something like {first: 0, rest: 0}. But that could easily be done, if one wanted that behavior.
What is a better solution?
First off, var [a, b] = f() works just fine in JavaScript 1.7 - try it!
Second, you can smooth out the usage syntax slightly using with():
var array = [1,2];
with (assign(array, { var1: null, var2: null }))
{
var1; // == 1
var2; // == 2
}
Of course, this won't allow you to modify the values of existing variables, so IMHO it's a whole lot less useful than the JavaScript 1.7 feature. In code I'm writing now, I just return objects directly and reference their members - I'll wait for the 1.7 features to become more widely available.
You don't need the dummy "_" variable. You can directly create "global" variables by using the window object scope:
window["foo"] = "bar";
alert(foo); // Gives "bar"
Here are few more points:
I wouldn't name this function
"assign" because that's too generic
a term.
To more closely resemble JS
1.7 syntax, I'd make the function take the destination as the first
argument and the source as the
second argument.
Using an object literal to pass the destination variables is cool but can be confused with JS 1.7 destructuring where the destination is actually an object and not an array. I prefer just using a comma delimited list of variable names as a string.
Here's what I came up with:
function destructure(dest, src) {
dest = dest.split(",");
for (var i = 0; i < src.length; i++) {
window[dest[i]] = src[i];
}
}
var arr = [42, 66];
destructure("var1,var2", arr);
alert(var1); // Gives 42
alert(var2); // Gives 66
Here's what I did in PHPstorm 10:
File -> Settings -> Languages & Frameworks -> ...
... set JavaScript language version to e.g. JavaScript 1.8.5...
-> click Apply.
In standard JavaScript we get used to all kinds of ugliness, and emulating destructuring assignment using an intermediate variable is not too bad:
function divMod1(a, b) {
return [ Math.floor(a / b), a % b ];
}
var _ = divMod1(11, 3);
var div = _[0];
var mod = _[1];
alert("(1) div=" + div + ", mod=" + mod );
However I think the following pattern is more idomatic:
function divMod2(a, b, callback) {
callback(Math.floor(a / b), a % b);
}
divMod2(11, 3, function(div, mod) {
alert("(2) div=" + div + ", mod=" + mod );
});
Note, that instead of returning the two results as an array, we pass them as arguments to a callback function.
(See code running at http://jsfiddle.net/vVQE3/ )

Categories

Resources