Javascript function as callback - javascript

The following script produces "Hello", "undefined", "Hello" message boxes:
function action(callback) {
window.setTimeout(callback, 1000);
}
var obj = {
text: "Hello",
f: function() { window.alert(this.text); }
};
obj.f(); // Line 1
action(obj.f); // Line 2
action(function() { obj.f(); }); // Line 3
I looking for explanation why the line marked as "Line 2" produces "undefined" output.

in JavaScript, this is not bound to the method (like in python). Line 2 results in just the function being called, and this is undefined or not obj

When you call line2: You are only passing the function into the parameter. Since you are only passing the function, not the whole object, when it is called, this in the function does not refer to obj, thus making this.text undefined.

Alot of JS libraries do something like this:
if (!Function.prototype.context) {
Function.prototype.context = function (object) {
var fn = this;
return function () { return fn.apply(object, arguments); };
};
}
To be able to pass/bind this to a handler.
So in your case you can do smthg like this
action(obj.f.context(obj));
and receive your 'Hello'. And yes, this is a general way to do something you done in step 3.

The second one you pass a function with no scope so this becomes the highest object in the scope chain. The third way you create a closure and call f on the object directly which leaves this with the proper scope.

Related

Why in JSX sometimes we use brackets and sometimes not? [duplicate]

I was handling a JavaScript file upload event. And I have the following initializer and the following function:
Initializer
$('#s3-uploader').S3Uploader({
allow_multiple_files: false,
before_add: progressBar.show,
progress_bar_target: $('.upload-progress-bar'),
remove_completed_progress_bar: false
}).bind("s3_upload_complete", function(e, content) {
console.log(content);
});
Function
var progressBar = {
show: function() {
$('.upload-progress-bar').show();
return true;
}
}
In the initializer, I noticed there is a difference if I do
before_add: progressBar.show v.s. before_add: progressBar.show(). With the parentheses, it will be called once even if it is bound to the before_add option, and without the parentheses it will not.
Is there an explanation for the behaviour I observed?
With parentheses the method is invoked because of the parentheses, and the result of that invocation will be stored in before_add.
Without the parentheses you store a reference (or "pointer" if you will) to the function in the variable. That way it will be invoked whenever someone invokes before_add().
If that didn't clear things up, maybe this will help:
function Foo() {
return 'Cool!';
}
function Bar(arg) {
console.log(arg);
}
// Store the >>result of the invocation of the Foo function<< into X
var x = Foo();
console.log(x);
// Store >>a reference to the Bar function<< in y
var y = Bar;
// Invoke the referenced method
y('Woah!');
// Also, show what y is:
console.log(y);
// Now, try Bar **with** parentheses:
var z = Bar('Whut?');
// By now, 'Whut?' as already been output to the console; the below line will
// return undefined because the invocation of Bar() didn't return anything.
console.log(z);
If you then take a look at your browsers' console window you should see:
Cool!
Woah!
function Bar(arg)
Whut?
undefined
Line 1 is the result of invoking Foo(),
Line 2 is the result of invoking Bar() "via" y,
Line 3 is the "contents" of y,
Line 4 is the result of the var z = Bar('Whut?'); line; the Bar function is invoked,
Line 5 shows that invoking Bar() and assigning the result to z didn't return anything (thus: undefined).
Functions are first-class in JavaScript. This means they can be passed around, just like any other parameter or value. What you're seeing is the difference between passing a function and passing the value said function returns.
In your example:
before_add: progressBar.show
You want to pass progressBar.show instead of progressBar.show() because the former represents a function (function () {$('.upload-progress-bar').show(); return true;}) whereas the latter represents a returned result (true).
Here's another example:
// All this function does is call whatever function is passed to it
var callAnotherFunction = function (func) {
return func()
}
// Returns 3 — that's all
var return3 = function () { return 3 }
// `callAnotherFunction` is passed `return3`
// so `callAnotherFunction` will `return return3()` === `return 3`
// so `3` is printed
document.write(callAnotherFunction(return3))
// `callAnotherFunction(return3())` is the same as `callAnotherFunction(3)`.
// This will print nothing because, in `callAnotherFunction`
// `func` is 3, not a function
// so it cannot be invoked, so nothing is returned
// and `document.write` doesn't print anything.
document.write(callAnotherFunction(return3()))

Difference of calling a function with and without parentheses in JavaScript

I was handling a JavaScript file upload event. And I have the following initializer and the following function:
Initializer
$('#s3-uploader').S3Uploader({
allow_multiple_files: false,
before_add: progressBar.show,
progress_bar_target: $('.upload-progress-bar'),
remove_completed_progress_bar: false
}).bind("s3_upload_complete", function(e, content) {
console.log(content);
});
Function
var progressBar = {
show: function() {
$('.upload-progress-bar').show();
return true;
}
}
In the initializer, I noticed there is a difference if I do
before_add: progressBar.show v.s. before_add: progressBar.show(). With the parentheses, it will be called once even if it is bound to the before_add option, and without the parentheses it will not.
Is there an explanation for the behaviour I observed?
With parentheses the method is invoked because of the parentheses, and the result of that invocation will be stored in before_add.
Without the parentheses you store a reference (or "pointer" if you will) to the function in the variable. That way it will be invoked whenever someone invokes before_add().
If that didn't clear things up, maybe this will help:
function Foo() {
return 'Cool!';
}
function Bar(arg) {
console.log(arg);
}
// Store the >>result of the invocation of the Foo function<< into X
var x = Foo();
console.log(x);
// Store >>a reference to the Bar function<< in y
var y = Bar;
// Invoke the referenced method
y('Woah!');
// Also, show what y is:
console.log(y);
// Now, try Bar **with** parentheses:
var z = Bar('Whut?');
// By now, 'Whut?' as already been output to the console; the below line will
// return undefined because the invocation of Bar() didn't return anything.
console.log(z);
If you then take a look at your browsers' console window you should see:
Cool!
Woah!
function Bar(arg)
Whut?
undefined
Line 1 is the result of invoking Foo(),
Line 2 is the result of invoking Bar() "via" y,
Line 3 is the "contents" of y,
Line 4 is the result of the var z = Bar('Whut?'); line; the Bar function is invoked,
Line 5 shows that invoking Bar() and assigning the result to z didn't return anything (thus: undefined).
Functions are first-class in JavaScript. This means they can be passed around, just like any other parameter or value. What you're seeing is the difference between passing a function and passing the value said function returns.
In your example:
before_add: progressBar.show
You want to pass progressBar.show instead of progressBar.show() because the former represents a function (function () {$('.upload-progress-bar').show(); return true;}) whereas the latter represents a returned result (true).
Here's another example:
// All this function does is call whatever function is passed to it
var callAnotherFunction = function (func) {
return func()
}
// Returns 3 — that's all
var return3 = function () { return 3 }
// `callAnotherFunction` is passed `return3`
// so `callAnotherFunction` will `return return3()` === `return 3`
// so `3` is printed
document.write(callAnotherFunction(return3))
// `callAnotherFunction(return3())` is the same as `callAnotherFunction(3)`.
// This will print nothing because, in `callAnotherFunction`
// `func` is 3, not a function
// so it cannot be invoked, so nothing is returned
// and `document.write` doesn't print anything.
document.write(callAnotherFunction(return3()))

Modifying Array.forEach to Automatically Set the Context to be the Caller

Is it possible to create an alternate of Array.forEach that automatically sets the context "this" to be the same context as when the method was invoked?
For example (not working, not sure why):
Array.prototype.each = function(fn) {
return this.forEach(fn, arguments.callee.caller);
}
function myFunction() {
this.myVar = 'myVar';
[1,2,3].each(function() {
console.log(this.myVar); // logs 'myVar'
});
}
Array.forEach already takes a context argument as the optional last parameter,
(function() {
this.myvar = "myvar";
[1,2,3,4].forEach(function(v) {
console.log("v:"+v);
console.log("myvar="+this.myvar);
}, this);
})();
See MDN forEach
Also, the above examples (if we're not dealing with methods on instances regarding this) work without using bind or the optional context argument for forEach, the following also works correctly:
function myFunction() {
this.myVar = 'myVar';
[1,2,3].forEach(function() {
console.log(this.myVar); // logs 'myVar'
});
}
myFunction();
Because javascript is functionally scoped, so the anonymous function can access the parent function's scope using this and it logs correctly. this only really becomes problematic as a context when dealing with instance methods.
The answer is no, a JavaScript function cannot determine the value of this in the caller.
You can bind the function passed with the current object, like this
function myFunction() {
this.myVar = 'myVar';
[1,2,3].forEach(function() {
console.log(this.myVar); // logs 'myVar'
}.bind(this));
}
In ECMA Script 6, you can use an Arrow function, like this
[1,2,3].forEach(() => {
console.log(this.myVar); // logs 'myVar'
});
An alternative to messing with the this variable when passing around callbacks, you could always just assign this to a new variable so child scoped functions can access it:
Array.prototype.each = function(fn) {
return this.forEach(fn, arguments.callee.caller);
}
function myFunction() {
var me = this;
me.myVar = 'myVar';
[1,2,3].each(function() {
console.log(me.myVar); // logs 'myVar'
});
}
now you don't have to remember to pass this as a second parameter
Firstly, it must be pointed out that myFunction is a constructor. Yet, the first letter in the identifier is not capitalized. Please call it MyFunction.
If a constructor is called without the new operator, this is bound to the global object, i.e. window in browsers. This makes the capitalization convention our only way of spotting such mishaps.
The following lines of code demonstrate this:
// After the original code...
myFunction();
console.log(window.myVar); // logs "myVar"
Secondly, to be able to apply functions on any array, instead of changing Array.prototype, consider the following:
var utils = {array: {}}; // utils.array is a container for array utilities.
utils.array.each = function (array, func) {
var i;
for (i = 0; i < array.length; i += 1) { func(array[i]); }
};
utils.write = function (s) {
console.log(s); // Alternatively, document.write(s);
};
utils.array.each([1, 2, 3], utils.write); // prints 1 2 and 3 (on separate lines)
Notice that we didn't use this and new. They make JavaScript look like Java, apart from that, they rarely serve a useful purpose.
While libraries may modify Object.prototype and Array.prototype, end-developers shouldn't.
Also, we should (ideally) be able to do something like:
utils.array.each([1, 2, 3], console.log); or
utils.array.each([1, 2, 3], document.write);.
But most browsers won't allow it.
Hope this helped.
If I understand your requirement correctly, then you are trying to override the "this".
I think this can help you.

On Javascript, why is a function that is not bound using bind() still binds to the object?

In the following code, the first function is not bound to obj, but the second function is, so f() returns fifi and g() returns Mark Twain as expected. But the 3rd attempt, it is by (obj.getCallBack) first, which is now a function, and then it is invoked, essentially it should be the same as the f case. But they do print out Mark Twain instead. Why are they not bound to obj using bind() but still got executed with this pointing to obj?
(the 4th attempt is just a usual invocation of a method, and this should bind to the object on which the method is invoked on).
(tested on the current Chrome, Firefox, and IE 9)
window.name = "fifi";
var obj = {
name: "Mark Twain",
getCallBack: function() {
return this.name;
}
}
var f = obj.getCallBack;
var g = f.bind(obj);
console.log(f);
console.log(f());
console.log(g);
console.log(g());
console.log((obj.getCallBack)());
console.log(obj.getCallBack());
You are forgetting that if a function is called as a property of some object, that object will be the this for the call. So:
obj.getCallBack() //The function referenced by `obj.getCallBack`
//is called as a property of `obj`, so obj will be `this`
//for the call
f() //The function referenced by f, is not called as a property of some object so
//`this` will depend on strict mode.
After these basic rules, the bound function will be invoked, which can be thought of as a proxy function (any shim does this) that uses .call/.apply to explicitly set the context for the target function. So the this value for the proxy function doesn't matter, but behind the scenes it was set by the basic rules.
Edit:
(obj.getCallBack) does not return the function as value, because getValue is not called.. So it is exactly the same as obj.getCallback and the first post applies.
So you can do this and not get an error:
(obj.getCallback) = 5;
As opposed to:
(function(){}) = 5; //invalid assignment
To complement Esailija's answer, the desired effect actually should be:
var obj = {
name: "Mark Twain",
getCallBack: function() {
return function() { return this.name; };
}
}
var f = obj.getCallBack();
var g = f.bind(obj);
console.log(f);
console.log(f());
console.log(g);
console.log(g());
console.log((obj.getCallBack())());
console.log(obj.getCallBack()());
console.log(obj.getCallBack().bind(obj)());
Then in this case, the third attempt will give fifi, and so will the 4th attempt. To get the name inside obj, the fifth attempt binds it and invoke it and will get Mark Twain.
But the method that returns the callBack function should bind it, so let's change the code to:
var obj = {
name: "Mark Twain",
getCallBack: function() {
return (function() { return this.name;}).bind(this); // <-- note here
}
}
and now all attempts, even f(), will return Mark Twain.

javascript - shortcut for calling a function at the same time it is defined

to call a function at the same time it's defined, i had been using:
var newfunc = function() {
alert('hi');
};
newfunc();
is the following the correct way of combining these 2:
var newfunc = function() {
alert('hi');
}();
There could be a number of reasons you wish to do this. I'm not sure what yours are, but let me introduce a couple of favourite patterns:
Pattern #1: A singleton. The function is executed and then becomes a singleton object for use by other components of your code.
var singletonObject = new function() {
// example private variables and functions
var variable1 = {};
var variable2 = {};
var privateFunction = function() {
};
// example public functions
this.getData = function() {
return privateFunction(variable1, variable2);
};
// example initialisation code that will only run once
variable1.isInitialised = true;
};
Pattern #2: Self-executing anonymous function ... handy for sooo many reasons!
// Declare an anonymous function body.
// Wrap it in parenthesis to make it an "expression.
// Execute it by adding "();"
(function(){})();
And here's an example that also creates a namespace for your objects.
I'm using "NS" as an example namespace:
// declare the anonymous function, this time passing in some parameters
(function($, NS) {
// do whatever you like here
// execute the function, passing in the required parameters.
// note that the "NS" namespace is created if it doesn't already exist
})(jQuery, (window.NS = window.NS || {}));
You can also set the context of a self-executing function by using .call or .apply instead of the usual parenthesis, like this:
(function($){
// 'this' now refers to the window.NS object
}).call(window.NS = window.NS || {}, jQuery);
or
(function($){
// 'this' now refers to the window.NS object
}).apply(window.NS = window.NS || {}, [jQuery]);
var newfunc = function f() {
alert("hi!");
return f;
}();
Having a named function expressions allows the function to recursively call itself or, in this case, return itself. This function will always return itself, however, which might be an annoyance.
No. Your second example will immediately call the anonymous function and assign its return value to newfunc.
adamse describes an approach which appears to work. I'd still avoid the approach as the two step process is easier to read and thus will be easier to maintain.
If I understand your question correctly, give this a try:
(f = function (msg) {
msg = msg ? msg : 'default value';
alert(msg); }
)();
f('I\'m not the default value!');
You'll get two alerts, the first one will say "default value" and the second will say "I'm not the default value. You can see it in action at jsBin. Click 'preview' to make it run.
you could do like this:
o = {};
o.newfunc = ( function() {
function f() {
alert('hi');
}
f();
return {
f : f
};
}
)();
then calling the function like:
o.newfunc.f();
will also render an alert message

Categories

Resources