How does "this" keyword work within a function? - javascript

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

Related

Shadowing `this` - lexical name resolution

EDIT: I think this isn't a duplicate; it being a hidden parameter, I wanted to ask about shadowing in relation to this, and lexical scoping, having read this SO Q/A re. shadowing.
I had thought that the meaning of the name this might be resolved kind of dynamically (in terms of scoping), so as to explain why it doesn't seem to me to be resolved lexically:
function foo() {return this;}
var a = {f: foo};
var b = {f: foo};
a.f() !== b.f();
a.f() !== foo();
a.f() !== window; //not strict mode
But then I read that every function receives this as an additional parameter, silently. (I realise arrow functions are different.)
Obviously helper() doesn't work as we might hope:
ob = {
meth: function(){
var helper = function() {return this;};
return helper();
}
};
ob.meth(); //Window or undefined
As far as I understand, rather than this being resolved by looking at the enclosing scope (the result being ob), instead the interpreter is calling helper() with this set to undefined (strict mode), silently passed as an argument.
So is the surrounding scope's this effectively being shadowed, hence lexical scoping is in fact in action?
You are correct. Except in the case of arrow functions, this is never resolved lexically. It always refers to one of the following:
the object upon which a function was called, such as valueOfThis.foo()
the first argument to apply or call, such as foo.apply(valueOfThis, params) or foo.call(valueOfThis, ...).
the DOM element, in the case of event handlers, such as <button onclick="alert(this.tagName.toLowerCase());"/>
the object being constructed, when a function is used as a constructor, such as Foo = function(){ ... }; new Foo()
the object bound to the function, if the function was created using bind, such as bar = function(){ ... this ...}; foo = bar.bind(valueOfThis); foo()
in a getter/setter, this refers to the object for which the property is being accessed or set, such as valueOfThis.someProperty = 123
window (usually) if none of the above cases, such as foo()
#Bergi provided a great reference for all these in the comments below.
In the case of bound functions, the function being called is actually a different function than was passed to the bind method, because the bind method creates a new function
So is the surrounding scope's this effectively being shadowed, hence lexical scoping is in fact in action?
Yes, one could view it from that perspective. The this bound to the helper scope shadows the one bound to the meth scope. (And if you had used an arrow function, it wouldn't).
However, you still need to remember that this is not an ordinary variable but a special keyword. It is only bound to function scopes, it's not writable, it has weird coerce-to-object semantics in sloppy mode, and it's always implicitly bound - as you say, a hidden parameter.
Unless you're trying to understand how this works in arrow functions (and their lexical resolution), the analogy with scopes and shadowing is pretty useless.

"this" and object literals in JavaScript [duplicate]

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

Javascript lost context when assigned to other variable

Why in javascript if you reference objects method to some variable it loses that objects context. Can't find any link with explanation what happens under the hood. Except this one which states:
‘this’ refers to the object which ‘owns’ the method which doesn't seam to be true.
var Class = function() {
this.property = 1
}
Class.prototype.method = function() {
return this.property;
}
var obj = new Class();
console.log(obj.method() === 1);
var refToMethod = obj.method; // why refToMethod 'this' is window
console.log(refToMethod() !== 1) // why this is true?
var property = 1;
console.log(refToMethod() === 1)
It depends on how a function is called. If a function is not referenced through being an attribute of an object (e.g. refToMethod) then it will be assigned the "Global context" which is window. However, when a function is an attribute of object (e.g. obj.method), we refer to it as a method, and it is implicitly assigned the context of it's parent object.
JavaScript's context is unlike many languages in that you can override it easily using either .call() or .apply(). Furthermore, ECMAScript 5 introduced a new .bind() method to allow you to create copies of methods which are always bound to the same context. See MDN for more.
var obj = new Class();
obj.method(); // 1;
var unbound = obj.method;
unbound(); // undefined;
// Call and Apply setting the context to obj.
unbound.apply(obj); // 1
unbound.call(obj); // 1;
// ECMAScript 5's bind
var bound = unbound.bind(obj);
bound(); // 1;
From Douglas Crockford's book JavaScript: The Good Parts
The this parameter is very important in object oriented programming,
and its value is determined by the invocation pattern. There are four
patterns of invocation in JavaScript: the method invocation pattern,
the function invocation pattern, the constructor invocation pattern,
and the apply invocation pattern. The patterns differ in how the bonus
parameter this is initialized
The Method Invocation Pattern
When a function is stored as a property of an object, we call it a
method. When a method is invoked, this is bound to that object. If an
invocation expression contains a refinement (that is, a . dot
expression or[subscript] expression), it is invoked as a method
In your example method invocation pattern is
console.log(obj.method() === 1);
and this in this case is bound to the object "Class" and it works as you expected.
The Function Invocation Pattern
When a function is not the property of an object, then it is invoked
as a function:
var sum = add(3, 4); // sum is 7
When a function is invoked with this pattern, this is bound to the
global object. This was a mistake in the design of the language. Had
the language been designed correctly, when the inner function is
invoked, this would still be bound to the this variable of the outer
function. A consequence of this error is that a method cannot employ
an inner function to help it do its work because the inner function
does not share the method’s access to the object as its this is bound
to the wrong value
In your case
var refToMethod = obj.method; // why refToMethod 'this' is window
console.log(refToMethod() !== 1) // why this is true?
refToMethod is bound to the global object "window" in this case
You can find more information about this at JavaScript “this” keyword
Because you only assigned the function method to the refToMethod. When it runs the context is window.
It becomes clear when you print the object and the reference to the function:
console.log(obj); // Prints -> Class {property: 1, method: function}
console.log(refToMethod);
// Prints
// function () {
// return this.property;
// }
In the context of the obj, what is this? It is the Class object, that has an attribute called property.
And what is this in the context of the refToMethod? It is the window object. Thats why your assert failed the first time and it is true the second time. When you declare:
var property = 1;
You are actually declaring an attribute to the window object.

Strange value for the "this" object

Regarding this code:
var name = "Jaguar";
var car = {
name:"Ferrari",
getName:function(){
return this.name;
}
};
alert((car.getName = car.getName)());
The output is: Jaguar.
Why does this object correspond to Window and not the object contained in the car variable?
It seems that the fact to reassign the object's function to itself leads to lose the assignment of this to the object when the function is called...
I'm trying to guess: Does it exist a kind of mechanism (using variable or other) that keep an eye on the non-reassignement of an object's function so that if that situation happens, this mechanism would prevent the assignement of the this keyword as usual (as being equals to the object)?
The reason is fairly subtle: this in JavaScript is determined entirely by how a function is called. To have this set to car during the call to getName, you have to call getName immediately upon retrieving it from the car object, like this:
car.getName() // or
car["getName"]()
(Or via Function#call or Function#apply, which let you specify the value for this explicitly.)
What you're doing in your example is effectively this:
// Set f to the result of the assignment expression,
// which is a reference to the getName function
var f = (car.getName = car.getName);
// Call it (separately)
f();
...which is different. Functions called in that way get this set to the global object (window, in browsers). (Except in strict mode; in strict mode this would be undefined.)
More (from my anemic blog):
Mythical methods
You must remember this
Does it exist a kind of mechanism (using variable or other) that keep an eye on the non-reassignement of an object's function so that if that situation happens, this mechanism would prevent the assignement of the this keyword as usual (as being equals to the object)?
I'm not entirely sure I follow that question, but if you want to have a function that always has a preset this value, then yes, there are a couple of ways to do that.
One is to use the new ES5 function bind:
var name = "Jaguar";
var car = {
name: "Ferrari"
};
car.getName = function(){
  return this.name;
}.bind(car);
alert((car.getName = car.getName)()); // "Ferrari"
bind returns a function that always has this set to the argument you give it.
The other way is to use a closure. And in fact, you can create a bind-like function in ES3 very easily:
function pseudoBind(func, thisArg) {
return function() {
return func.apply(thisArg, arguments);
};
}
That doesn't do everything bind does, but it does the this part. Then you'd have:
var name = "Jaguar";
var car = {
name: "Ferrari"
};
car.getName = pseudoBind(function(){
  return this.name;
}, car);
alert((car.getName = car.getName)()); // "Ferrari"
More on closures (again from the blog):
Closures are not complicated
In a future spec, we'll be getting a declarative way of creating functions that have a preset this value (so-called "arrow functions" because the syntax for them involves uses => rather than the function keyword).
Aaah, this resolution...Lets take a gander.
var toy = {
log : function () { console.log(this); }
};
toy.log() //logs the toy object
So far, it seems like this resolution is static: Wherever the method was defined in, that's its this value.
But! What if we do this:
var sneakyBastard = toy.log;
sneakyBastard(); //logs Window
this is bound to the object it's called with. In the case of toy.log, you called log in the context of the toy object. But, sneakyBastard has no set context, so it's as if you've called window.sneakyBastard.
Now let's take a goose (goose? gander? no...) at your expression:
(car.getName = car.getName)()
...and what does an assignment return? The assigned value, in this case, a function, car.getName. We can break this expression into two:
var returnedValue = (car.getName = car.getName);
returnedValue();
...and from here it's obvious.
Instead of calling getName from the context of an object, you're calling it from the context of the return result of the grouping operator (which in this case there's no context).
In JavaScript, when there's no clear context defined, a default is used. The default is...
the global object when in strict mode
undefined when not in strict mode
You have put your function call parenthesis (()) so they call the result of the expression (car.getName = car.getName) (which is the value (a function) assigned to car.getName)

Understanding Javascript scope with "var that = this" [duplicate]

This question already has answers here:
In Javascript, why is the "this" operator inconsistent?
(8 answers)
Closed 9 years ago.
Say I have the following property method in an object:
onReady: function FlashUpload_onReady()
{
Alfresco.util.Ajax.jsonGet({
url: Alfresco.constants.PROXY_URI + "org/app/classification",
successCallback: {
fn: function (o) {
var classButtonMenu = [],
menuLabel, that = this;
var selectButtonClick = function (p_sType, p_aArgs, p_oItem) {
var sText = p_oItem.cfg.getProperty("text");
that.classificationSelectButton.set("label", sText);
};
for (var i in o.json.items) {
classButtonMenu.push({
text: o.json.items[i].classification,
value: o.json.items[i].filename,
onClick: {fn: selectButtonClick}
});
}
this.classificationSelectButton = new YAHOO.widget.Button({
id: this.id + "-appClassification",
type: "menu",
label: classButtonMenu[0].text,
name: "appClassification",
menu: classButtonMenu,
container: this.id + "-appClassificationSection-div"
});
},
scope: this
},
failureMessage: "Failed to retrieve classifications!"
});
It took me some guess work to figure out that in the selectButtonClick function that I needed to reference that instead of this in order to gain access to this.classificationSelectButton (otherwise it comes up undefined), but I'm uncertain as to why I can't use this. My best guess is that any properties in the overall object that gets referenced within new YAHOO.widget.Button somehow looses scope once the constructor function is called.
Could someone please explain why it is that I have to reference classificationSelectButton with var that = this instead of just calling `this.classificationSelectButton'?
The most important thing to understand is that a function object does not have a fixed this value -- the value of this changes depending on how the function is called. We say that a function is invoked with some a particular this value -- the this value is determined at invocation time, not definition time.
If the function is called as a "raw" function (e.g., just do someFunc()), this will be the global object (window in a browser) (or undefined if the function runs in strict mode).
If it is called as a method on an object, this will be the calling object.
If you call a function with call or apply, this is specified as the first argument to call or apply.
If it is called as an event listener (as it is here), this will be the element that is the target of the event.
If it is called as a constructor with new, this will be a newly-created object whose prototype is set to the prototype property of the constructor function.
If the function is the result of a bind operation, the function will always and forever have this set to the first argument of the bind call that produced it. (This is the single exception to the "functions don't have a fixed this" rule -- functions produced by bind actually do have an immutable this.)
Using var that = this; is a way to store the this value at function definition time (rather than function execution time, when this could be anything, depending on how the function was invoked). The solution here is to store the outer value of this in a variable (traditionally called that or self) which is included in the scope of the newly-defined function, because newly-defined functions have access to variables defined in their outer scope.
Because this changes its value based on the context it's run in.
Inside your selectButtonClick function the this will refer to that function's context, not the outer context. So you need to give this a different name in the outer context which it can be referred to by inside the selectButtonClick function.
There's lexical scope: variables declared in functions and arguments passed to functions are visible only inside the function (as well as in its inner functions).
var x = 1; // `1` is now known as `x`
var that = this; // the current meaning of `this` is captured in `that`
The rules of lexical scope are quite intuitive. You assign variables explicitly.
Then there's dynamic scope: this. It's a magical thing that changes it's meaning depending on how you call a function. It's also called context. There are several ways to assign a meaning to it.
Consider a function:
function print() { console.log(this); }
Firstly, the default context is undefined in strict mode and the global object in normal mode:
print(); // Window
Secondly, you can make it a method and call it with a reference to an object followed by a dot followed by a reference to the function:
var obj = {};
obj.printMethod = print;
obj.printMethod(); // Object
Note, that if you call the method without the dot, the context will fall back to the default one:
var printMethod = obj.printMethod;
printMethod(); // Window
Lastly, there is a way to assign a context is by using either call/apply or bind:
print.call(obj, 1, 2); // Object
print.apply(obj, [ 1, 2 ]); // Object
var boundPrint = print.bind(obj);
boundPrint(); // Object
To better understand context, you might want to experiment with such simple examples. John Resig has very nice interactive slides on context in JavaScript, where you can learn and test yourself.
Storing it in a variable lets you access it in other scopes where this may refer to something else.
See https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this, http://www.quirksmode.org/js/this.html and What is the scope of variables in JavaScript? for more information about the this keyword.
The this reference doesn't work when a method of a class is called from a DOM event. When a method of an object is used as an event handler for onclick, for example, the this pointer points to the DOM node where the event happened. So you have to create a private backup of this in the object.
this is a keyword in javascript, not a default variable defined within every function, hence, as Gareth said, this will refer to the context in which the function is invoked, or the global object if there's no context.

Categories

Resources