JavaScript Binding - javascript

thank you if you can help. Source of code http://ejohn.org/apps/learn/#84
1) in line 3 of the program below, where it says return context[name] what does this mean? Im guessing that it means name is bound to the context as a result of the apply function? Is that correct?
2)If my guess in 1 is correct, why does it use the [] brackets? Is that just the syntax. When I look at it, it makes me think array or object?
3) When it says apply(context, arguments) is arguments not the same as name or is arguments both context and name together? to put it another way, in the language of the call bind(Button, "click") is arguments only "click" or is it both button and click?
4) I tried to rewrite line 3 by substituting name for arguments like this
return context[name].apply(context, name);
but it didn`t work anymore, which raises the questions
a)if it is returning name bound to context (i.e. context[name]), why isn`t it sufficient to just have apply(context,name)?
b) if arguments includes both name and context, is the third line of the function essentially
return context[name].apply(context, [context, name]);
c) if my assumption in 4(b) is correct, why would we effectively have to have context passed twice in order to bind name to context? which is to say, I dont understand why line 3 doesnt work if you just write apply(context, name) instead of apply(context,arguments)
function bind(context, name){
return function(){
return context[name].apply(context, arguments);
};
}
var Button = {
click: function(){
this.clicked = true;
}
};
var elem = document.createElement("li");
elem.innerHTML = "Click me!";
elem.onclick = bind(Button, "click");
document.getElementById("results").appendChild(elem);
elem.onclick();
assert( Button.clicked, "The clicked property was correctly set on the object" );
Click me!

It may be helpful to understand the basics of JavaScript objects before diving into the specifics. Any JavaScript property can be accessed with the bracket notation, or the dot notation (if it is a valid identifier). It can be confusing since arrays also use this notation. Say there is an object of cars and their makes,
var cars = { Ford: 2007, Honda: 2010, BMW: 2011 };
Then we can access their keys using the dot notation or the bracket notation
cars.Ford // 2007
cars["Honda"] // 2010
Next, remember that functions are first class citizens in JavaScript. So you could use them as ordinary variables including storing them as object property values, in arrays, etc. Let's replace the years in the previous cars example with actual functions,
var cars = {
Ford: function() { alert("2007"); },
Honda: function() { alert("2010"); },
BMW: function() { alert("2011"); }
};
The keys Ford, Honda, and BMW can still be accessed as in the previous example with the dot or bracket notation, with the only difference that this time a function will be returned instead of the integer year.
cars["BMW"] now returns a function which can be directly invoked as
cars["BMW"](); // or
cars.BMW(); // or
var name = "BMW";
cars[name]();
That's not all. There are still two more ways to execute a function - through apply and call. The difference between apply and call is subtle but you should read up more about them.
Finally, arguments represents an array-like object that contains the arguments passed in to a function. This is best demonstrated by an example,
function whatever() {
console.log(arguments);
}
whatever(1, 2); // [1, 2]
whatever("foo", "bar", 23, [4, 6, 8]); // ["foo", "bar", 23, [4, 6, 8]]
whatever(); // undefined
Without giving any names to the function parameters, we were able to log all the arguments passed to the function. Since it is an array like object, access each argument individually as arguments[0], arguments[1], etc.
And now to answer your questions,
1) in line 3 of the program below, where it says return context[name] what does this mean? Im guessing that it means name is bound to the context as a result of the apply function? Is that correct?
context[name] is similar to the cars['Ford'] example above. It is supposed to give a function which is then invoked by calling apply on it. When that function is called, inside the function this will refer to the object - context.
2) If my guess in 1 is correct, why does it use the [] brackets? Is that just the syntax. When I look at it, it makes me think array or object?
Hopefully this was answered above.
3) When it says apply(context, arguments) is arguments not the same as name or is arguments both context and name together? to put it another way, in the language of the call bind(Button, "click") is arguments only "click" or is it both button and click?
arguments has nothing to do with either context or name. It is simply a list of the arguments/parameters that the function was called with. Hopefully the above description cleared this as well.
4) I tried to rewrite line 3 by substituting name for arguments like this
return context[name].apply(context, name);
but it didn`t work anymore
It didn't work because apply expects the second argument to be an Array, and you passed it a String. Try return context[name].apply(context, [name]); instead.
which raises the questions
a) if it is returning name bound to context (i.e. context[name]), why isn`t it sufficient to just have apply(context,name)?
b) if arguments includes both name and context, is the third line of the function essentially
return context[name].apply(context, [context, name]);
arguments has nothing to do with the context, or name. Hopefully this was cleared up in the above examples.
c) if my assumption in 4(b) is correct, why would we effectively have to have context passed twice in order to bind name to context? which is to say, I dont understand why line 3 doesnt work if you just write apply(context, name) instead of apply(context,arguments)
The above answers already answer this part.

1) context[name] just means the property of the "context" object with that name. In the case of:
bind(Button, "click");
that works out to Button["click"], which is the click() function inside the Button object
2) All objects in Javascript are a collection of properties, which can be accessed by their names. Given the definition:
var Button = {
click: function(){
this.clicked = true;
}
};
both Button.click and Button["click"] would refer to the same thing - the function click() inside the Button object.
3) The arguments keyword refers to an array-like object containing all of the arguments passed to a function. In the example, bind() is returning a newly-created function. The "arguments" referred to in that function are whatever arguments that function gets called with. In this case, it's neither context nor name, it's whatever the onclick mechanism passes to the event handler.
Here's a slightly different way to write the code that sets up the event handler:
var elem = document.createElement("li");
elem.innerHTML = "Click me!";
var boundFunction=bind(Button, "click");
elem.onclick=boundFunction;
document.getElementById("results").appendChild(elem);
Maybe this makes it more clear that when you call bind(), it returns a new function. If you were to call the boundFunction like this:
boundFunction("these", "are", "arguments")
The use of arguments is inside the returned function, so arguments would be ["these", "are", "arguments"] in this case. The arguments that were passed to "bind" are used to construct the function that bind returns, so they're no longer relevant when the bound function gets called.
4) Until you understand the basics of how returning a function from another function works, this'll be pretty confusing. The purpose of apply() is to set the "this" keyword for a particular function invocation. Given the definition of Button, you might expect to be able to do this to set up the event handler:
elem.onclick = Button.click;
This doesn't work correctly, because when the event handling code calls the Button.click function, "this" is set to the global context, rather than to the Button instance. The purpose of the bind() function is to make a function that sets "this" appropriately, then calls the function you originally passed to bind().
I have a half-completed blog entry on this which might be a simpler example:
http://codemines.blogspot.com/2010/01/javascript-by-example-functions-and.html

Related

Confused about when to use `bind` in an Event Handler

The following successfully prints 'foo'.
var obj = {
name: 'foo',
printName: function printName() {
console.log(this.name);
}
};
var printButton= document.getElementById('printIt');
printButton.addEventListener('click', function(){
obj.printName();
});
The following doesn't, however:
printButton.addEventListener('click', obj.printName() );
I know the solution... simply use bind so that we're referencing the obj object. i.e:
printButton.addEventListener('click', obj.printName.bind(obj) );
Why then don't we need to use bind in the first example. I don't know why wrapping obj.printName() function call in the anonymous function results in the console.log correctly referencing and printing this properly, but when called directly after click, you needs to use bind
Alright, I commented with some good information on this question so I might as well answer!
Functions are first class
Okay, let's starts with some fundamentals of javascript that is very dissimilar to some other programming languages: in javascript functions are first class citizens--which is just a fancy way of saying that you can save functions into variables and you can pass functions into other functions.
const myFunction = function () { return 'whoa a function'; }
array.map(function () { return x + 1; });
And because of this wonderful feature, there is a big difference between the expressions:
Expression 1
obj.printName
and
Expression 2
obj.printName();
In expression 1: the function isn't being invoked so the value of the expression is of type function
In expression 2: the function is being invoked so the value of the expression is what the function returns. In your case, that's undefined
addEventListener
The method addEventListener takes in two arguments:
a string of the type of event
a function that will be run when the event fires.
Alight, so what does that mean?
When you call
// doesn't work
printButton.addEventListener('click', obj.printName() );
you're not passing a value of type function to the addEventListener method, you're actually passing undefined.
// works
printButton.addEventListener('click', obj.printName.bind(obj) );
then works (for one reason) because the second argument is actually of type function.
What does bind do? Why does it return a function?
Now we need to discuss what bind actually does. It related to the pointer* this.
*by pointer, I mean a reference identifier to some object
bind is a method that exists on every function object that simply binds the this pointer of a desired object to the function
This is best shown by an example:
Say you have a class Fruit that has a method printName. Now that we know that you can save a method into a variable, let's try that. In the example below we're assigning two things:
boundMethod which used bind
unboundMethod that didn't use bind
class Fruit {
constructor() {
this.name = 'apple';
}
printName() {
console.log(this.name);
}
}
const myFruit = new Fruit();
// take the method `printName`
const boundMethod = myFruit.printName.bind(myFruit);
const unboundMethod = myFruit.printName;
boundMethod(); // works
unboundMethod(); // doesn't work
So what happens when you don't call bind? Why doesn't that work?
If you don't call bind in this case, the value of the function that gets stored into the identifier unboundMethod can be thought to be:
// doens't work
const unboundMethod = function() {
console.log(this.name);
}
where the contents of the function is the same contents of the method printName from the Fruit class. Do you see why this is an issue?
Because the this pointer is still there but the object it was intended to refer to is no longer in scope. When you try to invoke the unboundMethod, you'll get an error because it couldn't find name in this.
So what happens when you do use bind?
Loosely bind can be thought of as replacing the this value of function with the object you're passing into bind.
So if I assign: myFruit.printName.bind(myFruit) to boundMethod then you can think of the assignment like this:
// works
const boundMethod = function() {
console.log(myFruit.name);
}
where this is replaced with myFruit
The bottom-line/TL;DR
when to use bind in an Event Handler
You need to use Function.prototype.bind when you want to replace the thises inside the function with another object/pointer. If your function doesn't ever use this, then you don't need to use bind.
Why then don't we need to use bind in the first example?
If you don't need to "take the method" (i.e. taking the value of type of function), then you don't need to use bind either Another way to word that is: if you invoke the method directly from the object, you don't need bind that same object.
In the wrapper function, you're directly invoking the method of the object (as in expression 2). Because you're invoking the method without "taking the method" (we "took" the methods into variables in the Fruit example), you don't need to use bind.
printButton.addEventListener('click', function(){
// directly invoke the function
// no method "taking" here
obj.printName();
});
Hope this helps :D
Note: You need to call printButton.addEventListener('click', obj.printName() ); without parenthesis in obj.printName() since you want to pass the function.
The answer lies in the way this is bound in Javascript. In JS, the way a function is called decides how this is bound. So when you provide the callback function like below:
printButton.addEventListener('click', function(){
obj.printName();
});
Notice, printName is being called via dot notation. This is called implicit binding rule when this is bound to an object before dot, in this case obj. Clearly in this case, you get the expected output.
However, when you call it like this:
printButton.addEventListener('click', obj.printName );
Notice that, all you are passing is the address of the function that is inside obj. So in this case info about obj is lost. In other words, the code that calls back the function doesn't have the info about obj that could have been used to set this. All it has is the address of the function to call.
Hope this helps!
EDIT:
Look at this crude implementation I call bind2 that mimics native bind. This is just to illustrate how native bind function returns a new function.
Function.prototype.bind2 = function (context) {
var callBackFunction = this;//Store the function to call later
return function () { //return a new function
callBackFunction.call(context);//Later when called, apply
//context, this is `obj` passed
//in bind2()
}
};
function hello() {
alert(this.name);
}
obj = {
name:'ABC'
};
var f = hello.bind2(obj);
f();
Notice: How function f() is hard bound here. f() has hard bound this with obj. You cannot change this to other than obj now. This is another thing with bind that probably will help you knowing.

In JavaScript, must bound parameters be in the anonymous function parameters?

Consider the code below, which works fine. It is the outcome of some debugging. It appears to work because I have inlcluded selectedRowNum not only in bind but it seems I am also required to include selectedRowNum as a parameter to the anonymous callback that is run by .end
Does this make sense? If I bind a variable, must I also include it as a param to the function I am binding it to?
for (var i = selectedRows.length; i--;) {
var selectedRowNum = selectedRows[i];
console.log('outer selectedRowNum');
console.log(selectedRowNum);
var url = urlbase + '/' + this.state.data[selectedRowNum].id;
request
.del(url)
.end(function(selectedRowNum, err, res) {
var data = this.state.data.slice();
data.splice(selectedRowNum, 1);
this.setState({data: data});
this.forceUpdate();
}.bind(this, selectedRowNum));
};
Yes, you need to.
The args values passed to the bind() will be prepended to the called functions param list, so you need to receive it in the target function as arguments.
A simple example will be
function x(p1, p2, p3) {
console.log(p1, p2, p3)
}
var fn = x.bind(window, 1);
fn(2, 3);
fn('a', 'b');
where we are passing an additional param 1 to the bind and when the binded function is called we are passing 2 and 3, now when we receive it in the method we need to have 3 parameters there.
How else do you expect to reference the bound value that you're trying to pass in?
function(selectedRowNum, err, res) { here selectedRowNum is simply a reference to the first argument that's passed in.
Well, technically the answer is no you don't need to. You could not list it as an argument, and refer to it as arguments[0]
Arguments are not absolutely required to be in the anonymous function declaration because you can access arguments via the arguments object as in arguments[0] and arguments[1].
But it is best to declare them as named arguments because it makes your code easier to read and write. If you don't declare them as named arguments in the anonymous declaration, then there is no symbolic name by which to refer to them and you are forced to use the arguments object to access them.
This is an important aspect of Javascript. Declaring named function arguments in a function declaration (whether anonymous or not) just gives you name by which you can refer to that specific argument. Since having a symbolic name is an important part of creating readable code, it is generally considered a good practice to follow.
When you use .bind() with arguments in addition to just the first argument, you are prepending more arguments to the actual function call. This will shift any other arguments later in the argument list. In order to access the correct argument, the anonymous function declaration must use the variables from the right spot in the argument list. If you don't include the extra variables that are added via .bind(), then your other arguments will be out of position and will have the wrong values.

Can you get the property name through which a function was called?

I've done a lot of searching and some playing around, and I'm pretty sure the answer to this question is no, but I'm hoping a JavaScript expert might have a trick up his sleeve that can do this.
A JavaScript function can be referenced by multiple properties, even on completely different objects, so there's no such thing as the object or property that holds the function. But any time you actually call a function, you must have done so via a single object (at the very least, the window object for global function calls) and property on that object.
(A function can also be called via a function-local variable, but we can consider the function-local variable to be a property of the activation object of the scope, so that case is not an exception to this rule.)
My question is, is there a way to get that property name that was used to call the function, from inside the function body? I don't want to pass in the property name as an argument, or closure around a variable in an enclosing scope, or store the name as a separate property on the object that holds the function reference and have the function access that name property on the this object.
Here's an example of what I want to do:
var callName1 = function() { var callName = /* some magic */; alert(callName); };
var obj1 = {'callName2':callName1, 'callName3':callName1 };
var obj2 = {'callName4':callName1, 'callName5':callName1 };
callName1(); // should alert 'callName1'
obj1.callName2(); // should alert 'callName2'
obj1.callName3(); // should alert 'callName3'
obj2.callName4(); // should alert 'callName4'
obj2.callName5(); // should alert 'callName5'
From my searching, it looks like the closest you can get to the above is arguments.callee.name, but that won't work, because that only returns the name that was fixed to the function object when it was defined, and only if it was defined as a named function (which the function in my example is not).
I also considered that maybe you could iterate over all properties of the this object and test for equality with arguments.callee to find the property whose value is a reference to the function itself, but that won't work either (in the general case), because there could be multiple references to the function in the object's own (or inherited) property set, as in my example. (Also, that seems like it would be kind of an inefficient solution.)
Can this be done?
Short answer:
No, you cannot get "the property name" used to call your function.
There may be no name at all, or multiple names across different scopes, so "the property name" is pretty ill defined.
arguments.callee is deprecated and should not be used.
There exists no solution that does not use arguments or closure.
Long answer:
As thefourtheye commented, you should rethink what you are trying to do and ask that instead in a new question. But there are some common misconceptions, so I will try to explain why you cannot get the "simple property name".
The reason is because it is not simple.
Before we go ahead, let us clarify something. Activation Objects are not objects at all.
The ECMAScript 5.1 specification calls them Environment Records (10.2.1), but a more common term is Scope chain.
In a browser the global scope is (often) the window object, but all other scopes are not objects.
There may be an object that you use to call a function, and when you call a function you must be in some scope.
With few exceptions, scopes are not objects, and objects are not scopes.
Then, there are many names.
When you call a function, you need to reference it, such as through an object property. This reference may have a name.
Scope chain has declarations, which always have a name.
A Function (the real function, not reference) may also have a function name - your arguments.callee.name - which is fixed at declaration.
Not only are they different names, they are not (always) the "the property name" you are seeking.
var obj = { prop : function f(){} }, func = obj.prop;
// "obj" and "func" are declarations.
// Function name is "f" - use this name instead of arguments.callee
// Property name is "prop"
func(); // Reference name is "func"
obj.prop(); // Reference names are "obj" and "prop"
// But they are the same function!
// P.S. "this" in f is undefined (strict mode) or window (non-strict)
So, a function reference may comes from a binding (e.g. function declaration), an Object (arguments.callee), or a variable.
They are all References (8.7). And reference does have a name (so to speak).
The catch is, a function reference does not always come from an object or the scope chain, and its name is not always defined.
For example a common closure technique:
(function(i){ /* what is my name? */ })(i)
Even if the reference does have a name, a function call (11.2.3) does not pass the reference or its name to the function in any way.
Which keeps the JavaScript engine sane. Consider this example:
eval("(new Function('return function a(){}'))()")() // Calls function 'a'.
The final function call refers the eval function, which refers the result of a new global scope (in strict mode, anyway), which refers a function call statement, which refers a group, which refers an anonymous Function object, and which contains code that expresses and returns a function called 'a'.
If you want to get the "property name" from within a, which one should it get? "eval"? "Function"? "anonymous"? "a"? All of them?
Before you answer, consider complications such as function access across iframes, which has different globals as well as cross origin restriction, or interaction with native functions (Function.prototype.bind for example), and you will see how it quickly becomes hell.
This is also why arguments.caller, __caller__, and other similar techniques are now all deprecated.
The "property name" of a function is even more ill defined than the caller, almost unrealistic.
At least caller is always an execution context (not necessary a function).
So, not knowing what your real problem is, the best bet of getting the "property name" is using closure.
there is no reflection, but you can use function behavior to make adding your own fairly painless, and without resorting to try/catch, arguments.callee, Function.caller, or other strongly frowned-upon behavior, just wasteful looping:
// returning a function from inside a function always creates a new, unique function we can self-identify later:
function callName() {
return function callMe(){
for(var it in this) if(this[it]===callMe) return alert(it);
}
};
//the one ugly about this is the extra "()" at the end:
var obj1 = {'callName2':callName(), 'callName3':callName() };
var obj2 = {'callName4':callName(), 'callName5':callName() };
//test out the tattle-tale function:
obj1.callName2(); // alerts 'callName2'
obj2.callName5(); // alerts 'callName5'
if you REALLY want to make it look like an assignment and avoid the execution parens each time in the object literal, you can do this hacky routine to create an invoking alias:
function callName() {
return function callMe(){
for(var it in this) if(this[it]===callMe) return alert(it);
}
};
//make an alias to execute a function each time it's used :
Object.defineProperty(window, 'callNamer', {get: function(){ return callName() }});
//use the alias to assign a tattle-tale function (look ma, no parens!):
var obj1 = {'callName2': callNamer, 'callName3': callNamer };
var obj2 = {'callName4': callNamer, 'callName5': callNamer };
//try it out:
obj1.callName2(); // alerts 'callName2'
obj2.callName5(); // alerts 'callName5'
all that aside, you can probably accomplish what you need to do without all the looping required by this approach.
Advantages:
works on globals or object properties
requires no repetitive key/name passing
uses no proprietary or deprecated features
does not use arguments or closure
surrounding code executes faster (optimized) than
a try/catch version
is not confused by repeated uses
can handle new and deleted (renamed) properties
Caveats:
doesn't work on private vars, which have no property name
partially loops owner object each access
slower computation than a memorized property or code-time repetition
won't survive call/bind/apply
wont survive a setTimeout without bind() or a wrapper function
cannot easily be cloned
honestly, i think all the ways of accomplishing this task are "less than ideal", to be polite, and i would recommend you just bite the coding bullet and pass extra key names, or automate that by using a method to add properties to a blank object instead of coding it all in an object literal.
Yes.
Sort Of.
It depends on the browser. (Chrome=OK, Firefox=Nope)
You can use a factory to create the function, and a call stack parsing hack that will probably get me arrested.
This solution works in my version of Chrome on Windows 7, but the approach could be adapted to other browsers (if they support stack and show the property name in the call stack like Chrome does). I would not recommend doing this in production code as it is a pretty brittle hack; instead improve the architecture of your program so that you do not need to rely on knowing the name of the calling property. You didn't post details about your problem domain so this is just a fun little thought experiment; to wit:
JSFiddle demo: http://jsfiddle.net/tv9m36fr/
Runnable snippet: (scroll down and click Run code snippet)
function getCallerName(ex) {
// parse the call stack to find name of caller; assumes called from object property
// todo: replace with regex (left as exercise for the reader)
// this works in chrome on win7. other browsers may format differently(?) but not tested.
// easy enough to extend this concept to be browser-specific if rules are known.
// this is only for educational purposes; I would not do this in production code.
var stack = ex.stack.toString();
var idx = stack.indexOf('\n');
var lines = ex.stack.substring(idx + 1);
var objectSentinel = 'Object.';
idx = lines.indexOf(objectSentinel);
var line = lines.substring(idx + objectSentinel.length);
idx = line.indexOf(' ');
var callerName = line.substring(0, idx);
return callerName;
}
var Factory = {
getFunction: function () {
return function () {
var callName = "";
try {
throw up; // you don't *have* to throw to get stack trace, but it's more fun!
} catch (ex) {
callName = getCallerName(ex);
}
alert(callName);
};
}
}
var obj1 = {
'callName2': Factory.getFunction(),
'callName3': Factory.getFunction()
};
var obj2 = {
'callName4': Factory.getFunction(),
'callName5': Factory.getFunction()
};
obj1.callName2(); // should alert 'callName2'
obj1.callName3(); // should alert 'callName3'
obj2.callName4(); // should alert 'callName4'
obj2.callName5(); // should alert 'callName5'

Javascript call() function - extra parameters

I'm reading Javascript: The Definitive Guide 6th Edition. It teaches ECMAscript 5. Anyway, it doesn't explain certain things thoroughly, like the call() function for example. This is about the extent of the book's definition:
Any arguments to call() after the first invocation context argument are the values that are passed to the function that is invoked. For example, to pass two numbers to the function f() and invoke it as if it were a method of the object o, you could use code like this:
f.call(o, 1, 2);
In the next section the author builds a map function. I've been studying Ruby so I know how map works. My question is about the implementation using the call() function. It looks like this:
var map = function(a,f, o) {
var results = [];
for(var i = 0, len = a.length; i < len; i++) {
if (i in a)
results[i] = f.call(o || null, a[i], i, a);
}
return results;
};
It then defines a square function and puts map to use:
function square(x){
return x*x;
}
var array = [1,2,3,4,5];
var results = map(array, square);
What is the purpose of the i, and a parameters in the call() function? If I remove them I get the same results.
Array.prototype.map is defined to pass the index and the array to the callback, just in case you need them. For example, instead of square(x), you could use Math.pow(base, exponent):
var results = [1, 2, 3, 4, 5].map(Math.pow);
console.log(results); // [1, 2, 9, 64, 625]
This map behaves in the same way. You don’t have to use the arguments if you don’t need them in a particular case.
Function.call allows you to call a function as though it were a method attached to an object.
What this means is you can have a function that is defined somewhere unrelated to an object, and then you can call that function as though it was a part of that object. This is a long way of saying that when you use Function.call, you are telling the JS engine to use the first parameter whenever you use 'this' inside the function.
So:
function set_field_value(name, value) {
// do stuff
this[name] = value;
}
makes no sense by itself, because the special variable 'this' is not set to anything (meaningful)
But, if you use call, you can set it to whatever you want:
// if my_object = some object:
set_field_value.call(my_object, 'firstname', 'bob');
console.log(my_object.firstname); // prints 'bob'
The only important argument to call is the first one, (in the above case, my_object) because the first argument becomes 'this' inside the function. The rest of the arguments are passed 'as is' to the function.
So - in your example, the i and a arguments are there to make the map function look like other map functions, which provide the array (a) and index (i) that are being worked on.
Hope that helps,
Jay
PS - I strongly recommend the book 'Javascript: the good parts' - it makes a lot more sense than the definitive guide.
f.call in this example equals to square.call, and square requires only one parameter(x), so i and a are totally redundant here (and not used). Only a[i] is used by the function.
However, since you can pass in any function you want as the second parameter of the map function, chances are there will be another function instead of square coming up in the book, and that function would require those additional two parameters as well. Or you can make one example yourself to try it.
function threeParams(a, b, c) {
return [a, b, c]; // simply puts the three parameters in an array and returns it
}
var array = [1,2,3,4,5];
var results = map(array, threeParams);
Your main confusion is not really about the call method. It's more about how javascript treats function arguments.
Forget about call for a moment and let's look at a regular function to minimize the number of things under consideration.
In javascript, functions are allowed to be called with more arguments than is specified. This is not considered an error. The arguments may be accessed via the arguments object:
function foo (arg1) {
alert('second argument is: ' + arguments[1]);
}
foo('hello','world'); // this is not an error
Javascript also allows functions to be called with fewer arguments than specified. Again, this is not considered an error. The unpassed arguments are simply given the value undefined:
function foo (arg1,arg2, arg3) {
alert('third argument is: ' + arg3);
}
foo('hello'); // this is not an error
That's all there is to it. When the function passed to map() is defined to accept one argument but map() calls it with three the remaining two arguments are essentially ignored.

context to use call and apply in Javascript?

Guys can any one explain context to use call and apply methods in Javascript?
Why to use call and apply instead of calling a function directly ?
You use call or apply when you want to pass a different this value to the function. In essence, this means that you want to execute a function as if it were a method of a particular object. The only difference between the two is that call expects parameters separated by commas, while apply expects parameters in an array.
An example from Mozilla's apply page, where constructors are chained:
function Product(name, price) {
this.name = name;
this.price = price;
if (price < 0)
throw RangeError('Cannot create product "' + name + '" with a negative price');
return this;
}
function Food(name, price) {
Product.apply(this, arguments);
this.category = 'food';
}
Food.prototype = new Product();
function Toy(name, price) {
Product.apply(this, arguments);
this.category = 'toy';
}
Toy.prototype = new Product();
var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);
What Product.apply(this, arguments) does is the following: The Product constructor is applied as a function within each of the Food and Toy constructors, and each of these object instances are being passed as this. Thus, each of Food and Toy now have this.name and this.category properties.
Only if you use call or apply you can modify the this context inside the function.
Unlike other languages - in JavaScript this does not refer to the current object - rather to the execution context and can be set by the caller.
If you call a function using the new keyword this will correctly refer to the new object (inside the constructor function)..
But in all other cases - this will refer to the global object unless set explicitly through call
You use .call() when you want to cause a function to execute with a different this value. It sets the this value as specified, sets the arguments as specified and then calls the function. The difference between .call() and just executing the function is the value of the this pointer when the function executes. When you execute the function normally, javascript decides what the this pointer will be (usually the global context window unless the function is called as a method on an object). When you use .call(), you specify exactly what you want this to be set to.
You use .apply() when the arguments you want to pass to a function are in an array. .apply() can also cause a function to execute with a specific this value. .apply() is most often used when you have an indeterminate number of arguments that are coming from some other source. It is often used too pass the arguments from one function call to another by using the special local variable arguments which contains an array of arguments that were passed to your current function.
I find the MDN references pages for .call() and .apply() helpful.
If you have experience with jQuery, you will know that most functions take use of the this object. For example, collection.each(function() { ... });
Inside this function, "this" refers to the iterator object. This is one possible usage.
I personally have used .apply() for implementing a queue of requests - I push an array of arguments into the queue, and when the time comes for executing it, I take an element, and pass it as the arguments for a handler function using .apply(), thus making the code cleaner then if having to pass an array of arguments as a first argument. That's another example.
In general, just keep in mind that those ways to call a function exist, and you may one day find them convenient to use for implementing your program.
If you have experience with Object Oriented Programming then call and apply will make sense if you compare it with inheritance and override the properties or method/functions of parent class from child class. Which is similar with call in javascript as following:
function foo () {
this.helloworld = "hello from foo"
}
foo.prototype.print = function () {
console.log(this.helloworld)
}
foo.prototype.main = function () {
this.print()
}
function bar() {
this.helloworld = 'hello from bar'
}
// declaring print function to override the previous print
bar.prototype.print = function () {
console.log(this.helloworld)
}
var iamfoo = new foo()
iamfoo.main() // prints: hello from foo
iamfoo.main.call(new bar()) // override print and prints: hello from bar
I can't think of any normal situation where setting the thisArg to something different is the purpose of using apply.
The purpose of apply is to pass an array of value to a function that wants those values as arguments.
It has been superseded in all regular everyday usage by the spread operator.
e.g.
// Finding the largest number in an array
`Math.max.apply(null, arr)` becomes `Math.max(...arr)`
// Inserting the values of one array at the start of another
Array.prototype.unshift.apply(arr1, arr2);
// which becomes
arr1 = [...arr2, ...arr1]

Categories

Resources