return this.foo("abc",function(){
//do something
});
Can some one tell me what does the above line do?
THanks
It grabs a reference to this, which might be the DOM Window, a DOM element, or any other JavaScript object depending on how and where the above code is being run.
It (skipping ahead) prepares a new anonymous Function that //does something.
It attempts to invoke a method foo on object this, passing in two parameters "abc" and said anonymous Function.
Very often when you see code that passes along an anonymous function (e.g. function(){ ... }), it is in fact holding on to that function in order to execute it not right away but at some later point in time, such as in response to a click event or a timer.
It calls the function referenced by this.foo and passes two parameters: The string "abc" and an anonymous function function(){ //do something}. It then returns the result.
It is equivalent to:
var a = "abc";
var b = function(){
//do something
};
return this.foo(a, b);
Functions are first class objects in JS so you can pass them around like any other value.
I recommend to have a look at the MDC JavaScript guide.
looks like this.foo() is a function that returns something. so the return value is, what this.foo() returns.
calls an instance method that gets as parameters a string and a function.
It will return (yeah, like it is in English) the returned result of a function this.foo(...) (in the most simple form, ithe function this.foo(...) return "something" then the code will return "something"). The function this.foo("abc", function(){...}); is itself a function which receives 2 arguments: A string "abc" and a function(). The function this.foo will do something and return "something" to return by the main function.
[x]
Related
I am reading an article on SitePoint (https://www.sitepoint.com/javascript-closures-demystified/) and there is an example of a first class function:
var foo = function() {
console.log("Hello World!");
};
var bar = function(arg) {
return arg;
};
bar(foo)();
The syntax of the last line looks puzzling to me, and I would have written it as:
bar(foo());
Does anyone know if either syntax is ok, or if there is a good reason for writing it the way the article wrote it? If so, please explain what that reason is.
Thanks,
William
Does anyone know if either syntax is ok,
There are completely different.
bar(foo)() calls bar, passing it foo as an argument, gets the return value of bar and then calls that return value as a function.
bar(foo()) calls foo, gets the return value of foo, then calls bar, passing it the return value of foo as an argument.
there is a good reason for writing it the way the article wrote it
It's a completely contrived example. There's no practical reason to involve bar in this at all. It is just showing that you can pass a function about like any other value (which your version doesn't do).
The term "first class functions" can typically be thought of as the ability to pass functions around the same way you would variables.
The last example is taking foo, which is a function, and passing it into bar(), another function. bar() returns yet another function and that is being called immediately after, hence the extra () at the end. So the way the example was written was not just a stylistic approach; it is showing how functions can be passed around, even into other functions.
bar(foo)();
Calls the function bar, using foo (a function, not the return value of the function) as the argument. Since bar returns the argument, bar ends up returning a function. Adding () at the end causes the returned function to be executed.
bar(foo());
Calls the function bar, using the return value of foo() as the argument
The reason why the code example shows a function being passed as an argument to another function, and being returned from the function is to showcase that functions are objects and can be passed around like one.
The two are fundamentally different and would achieve different things. Let's look at both.
bar(foo)();
This passes a reference to the function bar as the only argument to the function bar, which promptly returns the passed function as the return value, which is then executed via the final ().
Essentially, it's a laborious way of executing foo.
bar(foo());
This first executes foo and passes the return value - which is nothing - as the only argument to bar. Nothing further happens.
The result will be the same, but what the two syntax do are different. When writing bar(foo)();, bar returns a function and then you call this function. It means:
arg in the body of the bar method hold a reference to foo;
bar is executed before foo;
bar returns a function.
Writing bar(foo()), you first call foo and then pass its result to bar. It means:
arg in the body of the bar method holds a reference to the string "Hello World"
foo is called first
bar returns a string
When you write foo, you are referencing the function foo, not the value that this function returns. The function is not executed.
When you write foo(), you are executing the function and returning it's value.
So, when you say bar(foo)(), you are passing a function foo as an argument to bar. Since bar returns any argument it receives, this time it returns the function foo, and then it is being executed.
To simplify, this is what is happening:
var foo = function() {
console.log("Hello World!");
};
var bar = function(arg) {
return arg;
};
var returnFromBar = bar(foo);
returnFromBar();
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.
let's say I have I have the following in a file called file1.js:
//constructor
function Blah(){
this.string = "hello there agent ";
}
//'method'
Blah.prototype.greeting = function(num){
return this.string + num;
}
Then in a file called file2.js I then have this:
function combine(num,funct){
return funct(num);
}
And then finally, in an html file called file3, I have this:
var bond = new Blah();
document.write(combine(007,bond.greeting));
I am actually getting into the "greeting" method, but for some reason, the return value, instead of being a string, winds up not being NaN. Any idea why? the greeting() method seems to be ran at the proper time. However, despite that, 007 seems to be getting interpreted as NaN anyway. Again, any suggestions as to what could be causing this?
Thanks a bunch in advance
First, depending on how you call the greeting method, the this value will be different. If you call it like bond.greeting(num) then this will be bond. If you call it like funct(num), where funct is bond.greeting, then this will be the global object. You need to bind this permanently when passing the function along, to maintain its value no matter how you call the function.
Second, 007 === 7. If you want to print out 007 literally, then you should use a string:
combine('007', bond.greeting.bind(bond));
Remember, this depends on how the function gets called, it is dynamic, and resolved an runtime, unless you bind it previously, like we did above.
You're experiencing the special characteristics of the this keyword.
Basically, this resolves to whatever you call a function from. In your case, you're calling it from the global scope from through func(), which makes this == window. (Calling it through bond.greeting() makes this == bond.)
To resolve, this either bind the function or force the resolution:
// note that this method requires a shim for IE 8 and older
document.write(combine(007,bond.greeting.bind(bond)));
or
function combine(num, obj, funct){
// since funct is being called from obj, `this` == obj within the function
return obj[funct](num);
}
document.write(combine(007,bond, 'greeting'));
The problem you have is when you pass the function as argument, it is passed by value, and then you loose the reference to the object who has the element string = "hello there agent "; and when the function is executed, it executes "this.string" which doesn't exist inside the function, it returns undefined. It's a scope issue.
The solution to make it work good, is to pass the reference which is the object bond
function combine(num,obj){
return obj.greeting(num);
}
combine("007",bond); // returns "hello there agent 007"
1) NaN is "Not a number" error. Try encapsulating 007 in quotes
2) Do you need file2.js or could you do without it?
var bond = new Blah();
document.write(bond.greeting("007"));
I have a javascript function that takes an object as a parameter. I want one of the properties of passed object to be a function pointer. But the function is executed which I don't want to happen.
Example:
var myFuncPtr = function(){alert("Done");};
function myFunc(o){
// do something with passed object
// then call the function pointed at in the passed object
}
myFunc( {foo:"bar", onDone: myFuncPtr} );
I'm sure there's an expert out there who can guide me in the right direction. Am I going about this the wrong way. The quick solution is preferred if there is one.
Here is the actual code:
$(document).ready(function() {
imageCropper({
id:"imageBox",
editWidth:400,
cropWidth:0,
maxFileSize:3000000,
croppedId:"croppedBox",
onCrop:whenImageCropped
});
});
function whenImageCropped(o)
{
alert("done");
}
function imageCropper(options)
{
divId = options.id;
croppedDivId = (options.croppedId)?options.croppedId:divId+"_croppedPic";
$("#"+divId).load("/modules/imageCropper.asp", options, function(){
/* if i remove this bit, then no probs */
$("#"+divId+"_imgToCrop").Jcrop({
},function(){jcrop_api = this;}
);
/* end of - if i remove this bit, then no probs */
});
}
I want one of the properties of passed object to be a function pointer. But the function is executed which I don't want to happen.
That sounds like instead of passing a reference to the function, you are executing the function and passing the return value.
Maybe in your original code you have
myFunc( {foo:"bar", onDone: myFuncPtr()} );
which calls myFuncPtr and assigns the return value to onDone.
The code in the question is fine though, just call o.onDone() inside myFunc.
As already said, there are no pointers in JavaScript, it's much simpler than that. Functions are just data types such as strings, numbers, arrays etc, which happen to be callable.
var myFuncPtr = function(){alert("Done");};
function myFunc(o)
{
alert("Hello " + o.foo);
o.onDone();
}
myFunc( {foo:"bar", onDone: myFuncPtr} );
This does your trick. The onDone property of your object 'points' to the correct function, you can just call that.
Theerrrreee is no pointer in ECMAscript...... Asposx.yxm--dfgdfg.:!!
beside that... you might just want to call:
o.onDone();
within myFunc().
PS:
There is only reference in this language.
Why is it that when I use the dojo.hitch function and try to reference the "this" operator inside it, that it gives me reference to the wrong object?
console.debug(dijit.byId("widgetName")); //works as expected and prints out the window object
dojo.hitch(dijit.byId("widgetName"), tester())(); //this should be executing the tester function in the scope of the widget object
function tester() {
console.debug(this); //prints out the Javascript Window object instead of the widget object!!!!
}
Thanks
Based on what you have just shown, I can now safely provide an answer explaining what is wrong.
When you do a dojo.hitch() you should not call the function inside of it, but instead call the result of the function. That is, you need to provide dojo.hitch with a reference to the function to hitch, not the result of invoking that function.
In your example, you are calling tester() (which invokes the function tester) inside of the dojo.hitch(), which calls the tester once. Even though you have dojo.hitch()(); because tester() does not return a function handler (but the result of tester, in this case undefined), the hitch()(); does nothing. That might have been confusing so I will show you with an example.
Don't do this:
dojo.hitch( context, handler() )();
Instead do this:
dojo.hitch( context, handler )();
So to make what you have very readable you would do this:
widget = dijit.byId("widgetName");
tester = function() {
console.log(this);
}
handle = dojo.hitch(widget, tester);
handle();
Your mistake was trying to call the function from within the dojo.hitch(). This mistake also was not present in your original question.