Shadowing `this` - lexical name resolution - javascript

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.

Related

"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

Nested .bind not working as expected

Unfortunately .bind has been giving me grief when creating more complex closures.
I am quite interested in why .bind seems to work differently once you nest functions.
For example :
function t(){
t = t.bind({}); //correctly assigns *this* to t
function nested_t(){
nested_t = nested_t.bind({}); // fails to assign *this* to nested_t
return nested_t;
}
return nested_t();
}
//CASE ONE
alert(t());
// alerts the whole function t instead of nested_t
//CASE TWO
aleft(t.call(t));
// alerts the global object (window)
In both cases I was expecting a behavior like this:
function t(){
var nested_t = function nested_t(){
return this;
};
return nested_t.call(nested_t);
}
alert(t.call(t));
If someone could explain the behavior of .bind in the first (and/or) second case it would be much appreciated!
So, i'm not entirely reproducing your issue here (both cases return the global object), but i'll try and explain the code as i see it.
function t(){
t = t.bind({}); //correctly assigns *this* to t
function nested_t(){
nested_t = nested_t.bind({}); // fails to assign *this* to nested_t
return this;
}
return nested_t();
}
//CASE ONE
alert(t());
Let's take it step by step.
First, the function t() is defined. Then, upon call, it gets overwritten with a clean context. However, i don't see any usage of this context.
Now, a nested function (nested_t) is defined. Upon call, it is overwritten with a clean context. It then returns the context it had when it was called.
Back to t(). You then return the result of nested_t(), not nested_t itself. In the original function call, nested_t is still being called with global context.
Therefore, when you run t(), it returns the global object.
How your code works
It's very unclear, what your code is trying to do. You can find the documentation for .bind() here. It looks like you might be somehow misunderstanding what this is and how to use it. Anyway, what happens when you run your code is this:
A t function is created in global scope.
[case one] The t function is called.
Global scope t is replaced with a new value (original t bound to a specific context - anonymous empty object), which doesn't affect the current call in any way. Also, while the global t is overwritten, the local t is behaving as read-only. You can check it out by trying the following code: (function foo () { return (function bar () { bar = window.bar = 'baz'; return bar; })(); })() and comparing return value with window.bar.
The same thing happens with nested_t in the nested context (instead of global context).
Result of nested_t call is returned. nested_t returns the context it was called with, which was window, as no context was specified. Specifically, it was not called with an empty object context, because the .bind() inside didn't affect the call itself.
[case two] The exact same thing happens once again. Now you're just calling t with itself as context. Since t doesn't use its context (this) anywhere in its code, nothing really changes.
What your misconceptions might be
Basically, you're mixing up two things - function instance and function call context. A function is a "first-class citizen" in JavaScript - it's an object and you can assign values to its properties.
function foo () {
foo.property = 'value';
}
foo(); // foo.property is assigned a value
This has nothing to do with function call context. When you call a function a context is assigned to that call, which can be accessed using this (inside function body)
function foo () {
this.property = 'value';
}
var object = {};
foo.call(object); // object.property is assigned a value
When you use .bind(), you just create a new function with the same code, that is locked to a specific context.
function foo () {
this.property = 'value';
}
var fixedContext = {},
object = {};
bar = foo.bind(fixedContext);
foo.call(object); // fixedContext.property is set instead of object.property
But in this case, there are also function instances foo and bar, which can also be assigned properties, and which have nothing to do with contexts of calls of those functions.
Let's look at how bind works. First, one level of nesting:
var foo = function() { return this.x; };
alert(foo()); // undefined
alert(foo.bind({x: 42})()); // 42
Now we can add the next level of nesting:
var bar = function() { return foo.bind(this)(); };
alert(bar()); // undefined
alert(bar.bind({x: 42})());
We pass our this context to foo with - guess what? - bind. There is nothing different about the way bind works between scopes. The only difference is that we've already bound this within bar, and so the body of bar is free to re-bind this within foo.
As a couple of commenters have noted, functions that overwrite themselves are a huge code smell. There is no reason to do this; you can bind context to your functions when you call them.
I highly, highly recommend reading the documentation on bind, and trying to understand it to the point where you can write a basic version of Function.prototype.bind from scratch.

Difference in function scope and context

Does function in javascript have global and local scope?see the code below
function doSomething()
{
function foo()
{
alert(this);
}
foo();
}
foo();
Here function foo() does not get executed. But the "this" keyword within the function points to global window object,if function doSomething() is executed.That means the function foo() is executing on the global scope .since it is executing in global scope why cant we execute the nested function directly without first executing the doSomething().
You're confusing scope and context. The first is fixed for the given function (unless it's returned by some function, effectively being injected into the outer scope), the second (which, among other things, defines what this refers to inside this function) is given to the function when it's invoked - and in fact can be changed with call and apply.
Consider this:
var someObj = function() {
var internalObj = {
nam: 'internal',
doSomething: function() {
console.log('Called from ' + this.name);
}
}
internalObj.doSomething('Internal'); // 1
var someFunc = internalObj.doSomething;
someFunc(); // 2
return {
nam: 'external',
doSomething: internalObj.doSomething
}
}
var x = new someObj();
x.doSomething(); // 3
setTimeout(x.doSomething, 1000); // 4
setTimeout(x.doSomething.bind({nam:'a new one'}), 2000); // 5
JSFiddle.
In this example we define method 'doSomething' as property of internalObj variable, which is local to this constructor function - if you try to access it outside the someObj, you'll get ReferenceError.
When method is called in the constructor function itself (1), you'll get 'Called from internal' logged - as the method's context object (this) refers to internalObj now.
When we assign this method (its reference) to another local variable and call it from there (2), 'undefined' gets logged instead. Scope obviously didn't change here, but context variable did: it refers to the global object now.
Then we return this method as a result of constructor - and things start getting far more interesting: our function is now available in the outer scope! Note, though, the difference between results of its invokations in (3) and (4): the former gives us external (as the context object here is the one that was created by the constructor), the latter, again, return us undefined even though the syntax is the same. ) It happens because functions sent into timeout and event handlers "lose" their context, in short... unless we fix it with Function.prototype.bind method, like in (5).
JavaScript has function level scope.
Any function declaration will be scoped to its nearest containing function automatically.
Function expressions just return a value (that is a function) so you can scope them in any way you choose.
That means the function foo() is executing on the global scope
You are confusing scope and context.
Scope is determined by where a variable is declared (with var or a special rule like "function declarations are scoped"). It effects where a variable is visible.
Context is determined by how a function is called. It effects what the value of this is.
The two are not connected.

Why doesn't this closure have access to the 'this' keyword? - jQuery

I'm a beginner to closures (and Javscript in general), and I can't find a satisfactory explanation as to what's going on in this code:
function myObject(){
this.myHello = "hello";
this.myMethod = do_stuff;
}
function do_stuff(){
var myThis = this;
$.get('http://example.com', function(){
alert(this.myHello);
alert(myThis.myHello);
});
}
var obj = new myObject;
obj.myMethod();
It will alert 'undefined' and then 'hello'. Obviously this should not be jQuery specific, but this is the simplest form of my original code I could come up with. The closure in do_stuff() has access to the variables in that scope, but apparently this rule does not apply to the this keyword.
Questions:
What happens to this when the closure is passed outside the scope of do_stuff() (in this case $.get())? Does myThis contain a copy of this or a reference to it? Is it generally not a good idea to use this in closures?
Any response much appreciated.
What happens to this when the closure is passed outside the scope of do_stuff() (in this case $.get())?
Each function has its own execution context, the this keyword retrieves the value of the current context.
The doStuff identifier and the obj.myMethod property refer to the same function object, but since you are invoking it as a property of an object (obj.myMethod();), the this value inside that function, will refer to obj.
When the Ajax request has succeeded, jQuery will invoke the second function (starting a new execution context), and it will use an object that contains the settings used for the request as the this value of that callback.
Does myThis contain a copy of this or a reference to it?
The myThis identifier will contain a reference to the object that is also referenced by the this value on the outer scope.
Is it generally not a good idea to use this in closures?
If you understand how the this value is handled implicitly, I don't see any problem...
Since you are using jQuery, you might want to check the jQuery.proxy method, is an utility method that can be used to preserve the context of a function, for example:
function myObject(){
this.myHello = "hello";
this.myMethod = do_stuff;
}
function do_stuff(){
$.get('http://example.com', jQuery.proxy(function(){
alert(this.myHello);
}, this)); // we are binding the outer this value as the this value inside
}
var obj = new myObject;
obj.myMethod();
See also:
‘this’ object can’t be accessed in private JavaScript functions without a hack?
$.get('http://example.com', function(){
alert(this.myHello); // this is scoped to the function
alert(myThis.myHello); // myThis is 'closed-in'; defined outside
});
note the anonymous function. this in that scope is the scope of the function. myThis is the this of the outer scope, where the myHello has been defined. Check it out in firebug.
'this' always refers to the current scope of execution, i believe. If you want to take the current scope and preserve it, you do what you did, which is assign this to another variable.
$.get('http://example.com', function(){
// inside jQuery ajax functions - this == the options used for the ajax call
});
What happens to this when the closure is passed outside the scope of do_stuff() (in this case $.get())?
Nothing "happens" to it, this is still this for that closure, the execution context of the functions called from the closure do not automatically inherit this.
Does myThis contain a copy of this or a reference to it?
All non-scalar assignments are references in JavaScript. So it is a reference to this, if you change properties on either, they change for both.
Is it generally not a good idea to use this in closures?
It is generally a good idea to use this in closures, but if you're going to be using closures inside that need to access the same this, its good practice to do exactly what you did: var someName = this; and then access using someName

How does "this" keyword work within a function?

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

Categories

Resources