I was reading through some javascript posts, and I came across this answer.
Basically, in the answer, the poster said that you could set
window.onblur = myBlurFunction
only if myBlurFunction is a function that doesn't need any arguments passed to it.
I was about to comment that it was possible to use bind to perform partial application for functions requiring arguments, but when I tried
var myBlurFunction = console.log.bind(console,'blur');
window.onblur = myBlurFunction;
blurring the window didn't print the string "blur", but instead printed what seems to be a blur object
blur blur { target: Window → window-onblur-not-working, …
Does anyone know why this approach doesn't work?
What I'm really looking for with my question is why is the event handler function given the event as an argument?
window.onblur = function(event){console.log(event)}
I've never seen any documentation that mentions or explains the event parameter.
Also, how is the bound parameter overridden? Typically once a value is bound to a function parameter, any additional arguments will be assigned to the subsequent parameters:
var f = function(arg1,arg2){console.log(arg1,arg2)};
g = f.bind(null,1);
g(); // 1 undefined
g(2); // 1 2
g.call(null,2); // 1 2
Quoting the bind() page on MDN:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
Let's split those two concepts and then explain them together in your example.
Changing the this context
This is an adaptation of the example in the MDN page (I promise it's simple!):
// This assignment is equivalent to 'window.x' or 'var x' in the global scope
this.x = "global!";
var obj = {
x: "not global!",
getX: function() {
return this.x;
}
};
// Running inside the object's scope, returns obj.x
obj.getX();
//=> "not global!"
// Assign the scoped function (obj.getX) to a global variable
var retrieveX = obj.getX;
// Running in the global scope, returns window.x
retrieveX();
//=> "global!"
// Binds the 'retrieveX' function to run inside the object's scope
var boundedRetrieveX = retrieveX.bind(obj);
// Running inside the specified 'obj' scope, returns obj.x
boundedRetrieveX();
//=> "not global!"
From that, we gather that passing obj as an argument changes what context this refers to.
On your example, you're doing something like this:
console.log.bind(console); // The second argument doesn't matter for now
So you're telling console.log that any instances of this are a reference to the console context. Which I suppose is fine, shouldn't do much damage.
Prepending arguments
Again, adapting from the MDN page example:
function list() {
// Simply convers the arguments list into an Array, then returns it
return Array.prototype.slice.call(arguments);
}
// Example usage
list(1, 2, 3);
//=> [1, 2, 3]
// Using 'bind' to prepend to (append to the start of) the arguments list
// Note that, because 'this' context doesn't matter, the first argument is null
var betterList = list.bind(null, 98);
// Passing no arguments, it returns an array with only 98
// This is similar to '[98].concat([])'
betterList();
//=> [98]
// Passing arguments, it appends 98 to the start of the array
// Again, this is similar to '[98].concat([1,2,3])'
betterList(1, 2, 3);
// [98, 1, 2, 3]
// The parameters can go on indefinitely. They will all be added to the start of the arguments list in order
var bestList = list.bind(null, 98, 99, 100);
bestList(1, 2, 3);
//=> [98, 99, 100, 1, 2, 3]
The function list turns the Array-like object arguments, which contains all of the arguments passed to the function, into an actual Array.
With bind(), we append values to the start of that argument list, so that to the function, it seems as if they were already passed in that way in the first place.
Your code looks something like this:
console.log.bind(console, "blur");
Ignoring the first argument, you're prepending the arguments sent to console.log (which in this case is the event response) with "blur". Which also isn't harmful, just not very useful.
Final thoughts
So, here's a screenshot of me playing around with the arguments. The first argument, that indicates the context for this, is set to null, just like in the example above, because it doesn't actually matter here. And I've passed a long list of arguments afterwards to be prepended to the onblur event response.
As you can see, even though I added a bunch of stuff to the response, the Event object (not a blur object! haha) is still there.
So that is why it "doesn't" work. It works in its own way. That just might not be what you were expecting.
You can still go for approaches presented in the question you linked, such as
window.onblur = () => console.log("blur");
Solutions that are less complicated and actually do what you expect them to
Related
I just came across an interesting situation in JavaScript. I have a class with a method that defines several objects using object-literal notation. Inside those objects, the this pointer is being used. From the behavior of the program, I have deduced that the this pointer is referring to the class on which the method was invoked, and not the object being created by the literal.
This seems arbitrary, though it is the way I would expect it to work. Is this defined behavior? Is it cross-browser safe? Is there any reasoning underlying why it is the way it is beyond "the spec says so" (for instance, is it a consequence of some broader design decision/philosophy)? Pared-down code example:
// inside class definition, itself an object literal, we have this function:
onRender: function() {
this.menuItems = this.menuItems.concat([
{
text: 'Group by Module',
rptletdiv: this
},
{
text: 'Group by Status',
rptletdiv: this
}]);
// etc
}
Cannibalized from another post of mine, here's more than you ever wanted to know about this.
Before I start, here's the most important thing to keep in mind about Javascript, and to repeat to yourself when it doesn't make sense. Javascript does not have classes (ES6 class is syntactic sugar). If something looks like a class, it's a clever trick. Javascript has objects and functions. (that's not 100% accurate, functions are just objects, but it can sometimes be helpful to think of them as separate things)
The this variable is attached to functions. Whenever you invoke a function, this is given a certain value, depending on how you invoke the function. This is often called the invocation pattern.
There are four ways to invoke functions in javascript. You can invoke the function as a method, as a function, as a constructor, and with apply.
As a Method
A method is a function that's attached to an object
var foo = {};
foo.someMethod = function(){
alert(this);
}
When invoked as a method, this will be bound to the object the function/method is a part of. In this example, this will be bound to foo.
As A Function
If you have a stand alone function, the this variable will be bound to the "global" object, almost always the window object in the context of a browser.
var foo = function(){
alert(this);
}
foo();
This may be what's tripping you up, but don't feel bad. Many people consider this a bad design decision. Since a callback is invoked as a function and not as a method, that's why you're seeing what appears to be inconsistent behavior.
Many people get around the problem by doing something like, um, this
var foo = {};
foo.someMethod = function (){
var that=this;
function bar(){
alert(that);
}
}
You define a variable that which points to this. Closure (a topic all its own) keeps that around, so if you call bar as a callback, it still has a reference.
NOTE: In use strict mode if used as function, this is not bound to global. (It is undefined).
As a Constructor
You can also invoke a function as a constructor. Based on the naming convention you're using (TestObject) this also may be what you're doing and is what's tripping you up.
You invoke a function as a Constructor with the new keyword.
function Foo(){
this.confusing = 'hell yeah';
}
var myObject = new Foo();
When invoked as a constructor, a new Object will be created, and this will be bound to that object. Again, if you have inner functions and they're used as callbacks, you'll be invoking them as functions, and this will be bound to the global object. Use that var that = this trick/pattern.
Some people think the constructor/new keyword was a bone thrown to Java/traditional OOP programmers as a way to create something similar to classes.
With the Apply Method
Finally, every function has a method (yes, functions are objects in Javascript) named "apply". Apply lets you determine what the value of this will be, and also lets you pass in an array of arguments. Here's a useless example.
function foo(a,b){
alert(a);
alert(b);
alert(this);
}
var args = ['ah','be'];
foo.apply('omg',args);
Function calls
Functions are just a type of Object.
All Function objects have call and apply methods which execute the Function object they're called on.
When called, the first argument to these methods specifies the object which will be referenced by the this keyword during execution of the Function - if it's null or undefined, the global object, window, is used for this.
Thus, calling a Function...
whereAmI = "window";
function foo()
{
return "this is " + this.whereAmI + " with " + arguments.length + " + arguments";
}
...with parentheses - foo() - is equivalent to foo.call(undefined) or foo.apply(undefined), which is effectively the same as foo.call(window) or foo.apply(window).
>>> foo()
"this is window with 0 arguments"
>>> foo.call()
"this is window with 0 arguments"
Additional arguments to call are passed as the arguments to the function call, whereas a single additional argument to apply can specify the arguments for the function call as an Array-like object.
Thus, foo(1, 2, 3) is equivalent to foo.call(null, 1, 2, 3) or foo.apply(null, [1, 2, 3]).
>>> foo(1, 2, 3)
"this is window with 3 arguments"
>>> foo.apply(null, [1, 2, 3])
"this is window with 3 arguments"
If a function is a property of an object...
var obj =
{
whereAmI: "obj",
foo: foo
};
...accessing a reference to the Function via the object and calling it with parentheses - obj.foo() - is equivalent to foo.call(obj) or foo.apply(obj).
However, functions held as properties of objects are not "bound" to those objects. As you can see in the definition of obj above, since Functions are just a type of Object, they can be referenced (and thus can be passed by reference to a Function call or returned by reference from a Function call). When a reference to a Function is passed, no additional information about where it was passed from is carried with it, which is why the following happens:
>>> baz = obj.foo;
>>> baz();
"this is window with 0 arguments"
The call to our Function reference, baz, doesn't provide any context for the call, so it's effectively the same as baz.call(undefined), so this ends up referencing window. If we want baz to know that it belongs to obj, we need to somehow provide that information when baz is called, which is where the first argument to call or apply and closures come into play.
Scope chains
function bind(func, context)
{
return function()
{
func.apply(context, arguments);
};
}
When a Function is executed, it creates a new scope and has a reference to any enclosing scope. When the anonymous function is created in the above example, it has a reference to the scope it was created in, which is bind's scope. This is known as a "closure."
[global scope (window)] - whereAmI, foo, obj, baz
|
[bind scope] - func, context
|
[anonymous scope]
When you attempt to access a variable this "scope chain" is walked to find a variable with the given name - if the current scope doesn't contain the variable, you look at the next scope in the chain, and so on until you reach the global scope. When the anonymous function is returned and bind finishes executing, the anonymous function still has a reference to bind's scope, so bind's scope doesn't "go away".
Given all the above you should now be able to understand how scope works in the following example, and why the technique for passing a function around "pre-bound" with a particular value of this it will have when it is called works:
>>> baz = bind(obj.foo, obj);
>>> baz(1, 2);
"this is obj with 2 arguments"
Is this defined behavior? Is it
cross-browser safe?
Yes. And yes.
Is there any reasoning underlying why
it is the way it is...
The meaning of this is pretty simple to deduce:
If this is used inside a constructor function, and the function was invoked with the new keyword, this refers to the object that will be created. this will continue to mean the object even in public methods.
If this is used anywhere else, including nested protected functions, it refers to the global scope (which in the case of the browser is the window object).
The second case is obviously a design flaw, but it's pretty easy to work around it by using closures.
In this case the inner this is bound to the global object instead of to the this variable of the outer function.
It's the way the language is designed.
See "JavaScript: The Good Parts" by Douglas Crockford for a good explanation.
I found a nice tutorial about the ECMAScript this
A this value is a special object which is related with the execution
context. Therefore, it may be named as a context object (i.e. an
object in which context the execution context is activated).
Any object may be used as this value of the context.
a this value is a property of the execution context, but not a
property of the variable object.
This feature is very important, because in contrary to variables, this value never participates in identifier resolution process. I.e. when accessing this in a code, its value is taken directly from the execution context and without any scope chain lookup. The value of this is determinate only once when entering the context.
In the global context, a this value is the global object itself (that means, this value here equals to variable object)
In case of a function context, this value in every single function call may be different
Reference Javascript-the-core and Chapter-3-this
All the answers here are very helpful but I still had a hard time to figure out what this point to in my case, which involved object destructuring. So I would like to add one more answer using a simplified version of my code,
let testThis = {
x: 12,
y: 20,
add({ a, b, c }) {
let d = a + b + c()
console.log(d)
},
test() {
//the result is NaN
this.add({
a: this.x,
b: this.y,
c: () => {
//this here is testThis, NOT the object literal here
return this.a + this.b
},
})
},
test2() {
//64 as expected
this.add({
a: this.x,
b: this.y,
c: () => {
return this.x + this.y
},
})
},
test3() {
//NaN
this.add({
a: this.x,
b: this.y,
c: function () {
//this here is the global object
return this.x + this.y
},
})
},
}
As here explained Javascript - destructuring object - 'this' set to global or undefined, instead of object it actually has nothing to do with object destructuring but how c() is called, but it is not easy to see through it here.
MDN says "arrow function expressions are best suited for non-method functions" but arrow function works here.
this in JS:
There are 3 types of functions where this has a different meaning. They are best explained via example:
Constructor
// In a constructor function this refers to newly created object
// Every function can be a constructor function in JavaScript e.g.
function Dog(color){
this.color = color;
}
// constructor functions are invoked by putting new in front of the function call
const myDog = new Dog('red');
// logs Dog has color red
console.log('Dog has color ' + myDog.color);
Normal function or method
// Browswer example:
console.log(this === window) // true
function myFn(){
console.log(this === window)
}
myFn(); // logs true
// The value of this depends on the context object.
// In this case the context from where the function is called is global.
// For the global context in the browser the context object is window.
const myObj = {fn: myFn}
myObj.fn() // logs false
// In this case the context from where the function is called is myObj.
// Therefore, false is logged.
myObj.fn2 = function myFn(){
console.log(this === myObj)
}
myObj.fn2() // logs true
// In this case the context from where the function is called is myObj.
// Therefore, true is logged.
Event listener
Inside the function of an event handler this will refer to the DOM element which detected the event. See this question: Using this inside an event handler
I'm trying to understand JavaScript's arguments implicit variable in functions. Some tutorials delete the 0th element of it and say that it contains this but some other tutorials don't delete the 0th element. I'm very confused.
I wrote this code example and it shows that arguments doesn't contain this:
function aaa () {
console.log(arguments[0])
}
aaa(1,2,3);
Is it possible that sometimes arguments contains this? I wonder why some tutorials slice away the 0th element before using arguments.
most likely you have a function like blah(x) In which case you take off the first argument because it is already captured as the variable x, and you want the rest of the arguments that have been passed in.
The first argument is not this.
Arguments is an array* of the original arguments passed into the function, and doesn't directly have anything to do with the "this" variable.
That said, different tutorials probably try to explain how function references work, etc, using the scope (scope => "this" variable) of the function. This could easily involve passing an array and shifting off the first argument.
Consider this simple snippet:
var sample = function(a,b,c){
console.log(arguments, this);
};
sample(1,2,3);
Outputs:
[1, 2, 3], window
As we know by now, "this" is a special variable that has to do with the scope of the function. There are plenty of articles describing what it does/how it works, but in this context specifically, you've probably seen things used in a manner with .call or .apply:
sample.call(sample, 1, 2, 3)
or
sample.apply(sample, [1,2,3])
Those snippets both do the same thing - they convert the "this" scope of the function from the window object (since "sample" was declared as a global function) to the "sample" function itself, and pass the parameters 1, 2 and 3. They output:
[1, 2, 3], [sample function]
The reason some tutorials will shift off the first argument in this context is that there are often "helper" functions to make it more obvious when scope is changed, and many times those helper functions take, as their first parameter, the scope in which the new function is to be executed. So, they shift off the first parameter, and use that when (essentially) calling apply. A common example is bind(), like so:
Function.prototype.bind = function(scope){
var me = this,
args = Array.prototype.slice.apply(arguments, [1]);
return function () {
var handlerArgs = [];
for (i = 0; i < args.length; i++) {
handlerArgs.push(args[i]);
}
for (var i = 0; i < arguments.length; i++) {
handlerArgs.push(arguments[i]);
}
me.apply(scope, handlerArgs);
};
};
Now, you can call:
var bound = sample.bind(sample, 1);
bound(2,3);
...and get the output:
[1, 2, 3] [sample function]
You can see we're passing some parameters (the scope and the first parameter) when we bind the function initially, at which point we slice off the first argument ("sample", because that's the "scope" and has to be handled differently than any other arguments), then later, when bound() is invoked, push the 1, as well as 2 and 3, into the final arguments list.
It's a bit confusing at first, but hopefully that helps a little.
*Technically array-like.
I've been through a ton of posts and I finally got what I needed thanks to this:
$("a.foo").click(function(){
var that = this;
jPrompt("Type something:","","", function(r) {
$(that).text(r);
}
}
From the following:
Accessing $(this) within a callback function
I was wondering if someone could expand on what exactly is happening here (why is this not available without re-assigning?) and what core information I should read up on? From what I gather this might have something to do with closures... that's most of what I bumped into while searching around. Is that accurate?
In my case, I was looking to execute some code, then redirect once an ajax request completed. In the callback function I was running $(this).attr("href") which was returning undefined.
this is assigned by javascript according to how a function is called. So, it is the jPrompt() function that determines what value this will have in your callback when jPrompt() calls the callback.
So, unless jPrompt goes out of its way to keep the same value for this via some argument you passed in, it will likely have a different value. As such, you can save it away for access within the callback as you've done. This is a very common design pattern in javacscript callbacks.
FYI, some of the ways that this is assigned:
obj.method() - this in method() will be set to obj
func.call(obj) - this in func() will be set to obj
func() - this will be set to window in func() or undefined in strict mode
The meaning of this changes depending on where you're at. The this within a handler for your click event means something other than the this within the callback passed to your jPrompt function.
For what it's worth, you don't need to re-assign this, since the event object passed into your handler will have a reference to the currentTarget:
$("a.foo").on("click", function (event) {
// 'this' here refers to the anchor we clicked
jPrompt("Type something:", "", "", function (r) {
// 'this' here refers to whatever jPrompt instructs
$(event.currentTarget).text(r);
}
}
The code in the question with some added comments:
$("a.foo").click(function(){
var that = this; //`this` holds the a object clicked. now so does `that`!
jPrompt("Type something:","","", function(r) {
//even if `this` has a different value here, `that` still holds the a object clicked
$(that).text(r);
}
}
This is something you will often find yourself doing in similar situations. this is context-dependent and you often need to keep the value this had in one context and use it in another.
A quote from the ECMAScript specification:
10.1.7 This
There is a this value associated with
every active execution context. The
this value depends on the caller and
the type of code being executed and is
determined when control enters the
execution context.
Hope that answers your question. You also asked for a resource for further reading. Please visit:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this
These guys provide excellent documentation both detailed and typically quite accurate (unlike other popular sources of reference that often comes first in Google searches -- w3cshools.com I am thinking of you!).
A Short Overview of this
this in JavaScript is dynamically scoped. Its behavior differs from all other variables which are lexically scoped. Other variables don't have a different binding depending on how the function is called; their scope comes from where they appear in the script. this however behaves differently, and can have a different binding depending not on where it appears in the script but on how it's called. Consequently, it can be a source of confusion for people learning the language, but mastering it is necessary in order to become a proficient JavaScript developer.
Since this is dynamically bound there are several ways to change its values based on how you call the function.
Examples
When you execute a function in JavaScript, the default this is window.
function foo() {
console.log(this);
}
foo(); // => window
The this value can be changed in a number of ways. One way is to call the function as a method of an object:
var x = {
foo: function() {
console.log(this);
}
};
x.foo(); // => This time it's the x object.
Another way is to use call or apply to tell the function to execute in the context of a certain object.
function foo() {
console.log(this);
}
foo.call(x); // => x object again
foo.apply(x); // => x object as well
If you call or apply on null or undefined, the default behavior will occur again: the function will be executed in the context of window:
function foo() {
console.log(this);
}
foo.call(null); // => window
foo.apply(undefined); // => window
However, note that in ECMAScript 5 strict mode, this does not default to window:
(function() {
'use strict';
function foo() {
console.log(this);
}
foo(); // => undefined
foo.call(null); // => null
foo.apply(undefined); // => undefined
})();
You can also set the this by using bind to bind the function to an object before it is called:
function foo() {
console.log(this);
}
var bar = {
baz: 'some property'
};
var foobar = foo.bind(bar);
foobar(); // => calls foo with bar as this
Going Father: Lazy Bind / Uncurrying this
Going further, you may sometimes want to take functions which act on a this and allow the this value to be passed in as the first argument to the function. This can be really helpful for Array methods, such as forEach. For instance, let's say you are dealing with an object which is array-like but not actually an array.
var arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
'length': 3
};
If you want to iterate over this object with forEach, you could use call:
Array.prototype.forEach.call(arrayLike, function(item) {
console.log(item);
});
// Logs: a, b, c
However, another option is to create a forEach function which can be called directly on your object:
var forEach = Function.prototype.call.bind(Array.prototype.forEach);
Now you can use this function anytime you want to iterate over an array-like object:
forEach(arrayLike, function(item) {
console.log(item);
});
// Logs: a, b, c
Sometimes this method is referred to as "uncurrying this". However, I prefer to create a function which can generate these "uncurried" functions and call it "lazy binding".
var lazyBind = Function.prototype.bind.bind(Function.prototype.call);
var forEach = lazyBind(Array.prototype.forEach);
var slice = lazyBind(Array.prototype.slice);
var map = lazyBind(Array.prototype.map);
forEach(arrayLike, function(u) {
console.log(u);
});
// Logs: a, b, c
var realArray = slice(arrayLike);
// Converts arrayLike into a real array
forEach(
map(arrayLike, function(u) {
return u + 'Q';
}),
function(u) {
console.log(u);
}
);
// Logs: aQ, bQ, cQ
One really awesome thing about this technique is it can be useful for creating securable JavaScript, which can be helpful if you don't want other scripts on the page snooping around your internal variables. This is a pretty advanced meta-programming technique, though, and you don't see it in day-to-day JavaScript.
Observe the following:
function array_map(array, callback) {
for (var i = 0; i < array.length; i += 1) {
callback(array[i]);
}
}
var a = [], b = [];
array_map([1, 2, 3], function (x) { a.push(x); });
// just gives a = [1, 2, 3] as expected
// but why does this not work: ?
array_map([1, 2, 3], b.push);
// Chrome: a = [], Firefox: can't convert undefined to object
I do understand why this happens, namely: push is no longer bound to b (but to the global object) if you pass it to array_map directly. I don't really understand why Chrome doesn't give an error, at least Firefox seems to give some kind of error.
How can I detect if a function like this is passed to array_map to avoid these kinds of bugs?
I'm hoping there are advanced reflection techniques available to trace the origin of a function. For instance b.push.constructor gives Function, but that's not what I'm looking for.
I'm not sure what you expect there to happen. Array.prototype.map requires a function as second parameter, which returns a new value for every iteration.
Passing in just a function reference (which you do in your second example) doesn't tell the function what it has to do anyway. So you're kinda expecting that .map() applies some black magic and calls the passed in method with the correct parameter, which it obviously, can't do.
I totally didn't get that you wrote your own mapping function. However, your problem there is that you're losing scope of that .push() function. Only if you call it on the Array / Object like xxx.push(), the this within the called function will correctly reference the target object. Once you just passed the reference, this will either point to global / window or undefined and won't work anymore.
So solve that issue you could call it like
array_map([1, 2, 3], b.push.bind(b));
which also would apply an ES5 function. You can't really detect for it within the array_map(). A function is a function, your best shot would be to detect whether or not the passed in method is a native or not, but I wouldn't recommend that.
Usually these sorts of functions would allow you to set the context of the callback.
If you change your array_map function to accept a context, then it will work like this.
function array_map(array, callback, context) {
for (var i = 0; i < array.length; i += 1) {
callback.call(context, array[i]);
}
}
var b = [];
// now the push method is called from the b context
array_map([1, 2, 3], b.push, b);
The problem is, that Javascript has no such thing like "methods" - a function exclusively bound to a certain object. In your first example you pass a function which invokes a.push. this is bound to a here because you invoke it directly on a.
In your second code you just pass the function push without the context of b - this will be bound to the execution context which is the gloabl object.
You need to bind the the context of the function like the following:
array_map([1, 2, 3], b.push.bind(b));
or jQuery's proxy(). I can't find another simple solution at the moment but the one to hand over the context directly in a third parameter: function array_map(array, callback, context)
Have a look at this:
var a = {
b: function() {
console.log(this);
}
}
// Example 1
a.b(); // a
// Example 2
eval('a.b()'); // a
// Example 3
setTimeout('a.b()', 100); // a
// Example 4
setTimeout(a.b, 100); // Window
// Example 5
var c = a.b;
c(); // Window
jsFiddle.
Assuming the expected result is what I expected...
Example 1
When calling b(), the property of an Object, this becomes the property's Object, here it's the parent a. It produces the expected result.
Example 2
eval() is meant to adopt its execution context of where it is called, in this case, window. It also produces the expected result.
Example 3
When passing a string to setTimeout(), I'd imagine it is ran through something very similar to eval(). It too produces the expected result.
Example 4
this becomes Window in this example. This is what I am interested in.
Example 5
Here the this becomes Window, because c's parent object is Window.
When passing only a reference to a function (e.g. a.b), will its this always be Window when called with ()?
Is the only way to keep its this as a to pass it as a string to setTimeout() / setInterval()?
When passing only a reference to a function (e.g. a.b), will its this always be Window when called with ()?
Yes
Is the only way to keep its this as a to pass it as a string to setTimeout() / setInterval()?
No. Create a new function instead.
setTimeout(function() { a.b() }, 100);
Developers are often confused about javascript's this keyword. The most important thing to remember is that it is provided by the call.
In the 4th example:
// Example 4
setTimeout(a.b, 100); // Window
the first argument is a reference to the function, so it's called without any "parent" object. Since the call doesn't provide an object, this is set to window.
Your comment on example 5:
Here the this becomes Window, because
c's parent object is Window.
is not really incorrect. Because the function call doesn't provide an object to use as this, it is set to window (which is the default when no object is provided).
Is the only way to keep its this as a
to pass it as a string to setTimeout()
/ setInterval()?
No. Other than calling it as a property of an object, you can use call or apply:
var x = a.b;
x.call(a);