This question already has answers here:
Methods in ES6 objects: using arrow functions
(6 answers)
Lexical context of 'this' in Nested Object Literals
(2 answers)
Closed 3 years ago.
trying to learn the 'this' key word inside an arrow function properly.
after reading and watching some videos i understood that with the regular function the 'this' key word will be defined whenever the function is invoked.
and 'this' inside the arrow function will be defined according to the value of 'this' wherever you build that function.
so i opened the console and played with two objects and the two functions.
i did this:
const reg = {
reg1: "reg1",
reg2: {
reg3: 'reg3',
regFunc: function(){console.log(this)}
}
}
const arrow = {
arrow1: "arrow1",
arrow2: {
arrow3: 'arrow3',
arrowFunc: () => {console.log(this)}
}
}
reg.reg2.regFunc()
VM712:5 {reg3: "reg3", regFunc: ƒ}
arrow.arrow2.arrowFunc()
VM712:13 Window {parent: Window, opener: null, top: Window, length: 1, frames: Window, …}
for the reg Object i get it because it was invoked inside the reg2 object which it shows me.
but for the arrow Object the this keyword in the arrow function was created inside the arrow2 object inside arrow.
so why isn't the value of it in the arrow object arrow2? why is it the global window?
this is defined for a function execution context.
In the code that defines const arrow there is no function context, only the arrow function. So the lexical this is the global object (in sloppy mode) or undefined in strict mode.
It is a common misunderstanding that an object literal (the one assigned to arrow or to arrow2) would somehow bind this to it.
In arrow functions this is treated similarly to a normal variable (a constant one). An arrow function records the value of this at the moment of creation and this will always point to that value inside the arrow function (since you can't reassign this).
Because arrow functions do not bind their own this but instead inherit from the parent scope which in this case is the global object
The this pointer points window object as it is parent. And this in arrow functions always points to the parent scope, here it is window object.
If you wrap that arrow function with class or function(for instance), then this will point that object.
const func = {
b: {
d: function() {
console.log(this)
}
}
}
const arrow = {
b: {
d: function() {
const e = () => {
console.log(this)
}
return e()
}
}
}
func.b.d() >> {d:f}
arrow.b.d() >> {d:f}
Related
I think JavaScript ES6's arrow functions have two changes:
get rid of the "lost binding issue".
make this not bind to foo when foo.fn() is called.
For (1) above, the following code can illustrate (running inside of Node console):
var peter = {
name: "Peter Pan",
greetLater: function() {
setTimeout(function() {
console.log("Hi my name is", this.name);
}, 0);
}
};
peter.greetLater(); // => Hi my name is undefined
var michael = {
name: "Michael J Fox",
greetLater: function() {
setTimeout(() => {
console.log("Hi my name is", this.name);
}, 0);
}
};
michael.greetLater(); // => Hi my name is Michael J Fox
For (2) above, the following code can illustrate:
var winona = {
name: "Winona Ryder",
greet: function() {
console.log("Hi my name is", this.name);
}
};
winona.greet(); // => Hi my name is Winona Ryder
var demi = {
name: "Demi Moore",
greet: () => {
console.log("Hi my name is", this.name);
}
};
demi.greet(); // => Hi my name is undefined
I can understand (1) is a good thing as it solves the "lost binding" issue. But (2) is like "cutting the binding". It might seem that (2) is to solve the issue of (1), which is to go up the lexical scope to find this, but I think having (1) and not having (2) can co-exist: that is, when foo.fn() is called, the this inside the code of fn() can still refer to foo.
What is wrong with when foo.fn() is called, the this inside the code of fn() can still refer to foo, and when it is "dangling function", as in the SetTimeout() in (1) above, or in the following code:
winonaGreet = winona.greet;
winonaGreet(); // => Hi my name is undefined
then it uses the new behavior of going up the lexical scope to find the this? Isn't this more coherent with everything?
That is, when it is fn() or passed to SetTimeout and stored as fn and later invoked as fn(), then look up the lexical scope, but for foo.fn(), it just make a lot of sense to bind this to foo instead of looking up the lexical scope.
Why would we have 2 new rules, one to keep the binding and one to cut it?
And it seems for (2), the ways we can still call foo.fn() and have this inside of fn() bind to foo is to not use arrow function, or use ES6's class, as in Mozilla's example:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
}
but then, when we have (1), why do we have (2) also? It is like a hybrid of most other languages, where if foo.fn() is called, the this is always bound to foo.
this and Arrow Functions:
Arrow functions, introduced in ES6, provides a concise way to write functions in >JavaScript.
Another significant advantage it offers is the fact that it does not bind its own this. In other words, the context inside arrow functions is lexically or statically defined.
What do we mean by that?
Unlike other functions, the value of this inside arrow functions is not dependent on how they are invoked or how they are defined.It depends only on its enclosing context.
Thus, regardless of whether the arrow function was called using function invocation or method invocation, it retains the value of this from its enclosing context.In other words, an arrow function’s this value is the same as it was immediately outside it.
If used outside any enclosing function, an arrow function inherits the global context, thereby setting the value of this to the global object.
In classic function expressions, the this keyword is bound to different values based on the context in which it is called.
There are a few subtle differences in behavior between ordinary function functions and arrow functions. Arrow functions do not have their own this value. The value of this inside an arrow function is always inherited from the enclosing scope.
Arrow Functions lexically bind their context so this actually refers to the originating context.
There are a few other differences: arrow functions don’t get their own arguments, super, or new.target keywords. Arrow functions are anonymous, which means that they are not named, so if your function needs to have a self-reference at any point (e.g. recursion, event handler that needs to unbind), it will not work.
More info https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/
A scope in JS is associated to a function. When you create an object using new, this is created in constructor.
const foo = new Foo();
foo.fn()
In above code, context is created in constructor and fn derives its context from foo.
How does this work?
A function has an internal property [[prototype]], which stores context. By default it is not set (or set to default global scope) and it derives/ overrides context via caller. So in foo.fn(), context refers to foo. But if you do var fn = foo.fn; fn(), here context is of global/default scope.
To avoid this, we use Arrow function. Arrow function does not have an internal context and uses the context it is defined in. So above code var fn = foo.fn; fn(); will work.
However, if you define Arrow function inside an object literal, it will still point to the parent scope it was defined in and will not fallback to object.
Sample:
function Foo1() {
this.fn = function () {
console.log(this.constructor.name, this);
}
}
var foo2 = {
fn: function() {
console.log(this.constructor.name, this);
}
}
function test() {
var foo3 = {
fn: function() {
console.log(this.constructor.name, this);
}
}
foo3.fn();
}
function test2() {
var foo3 = {
fn: () => {
console.log(this.constructor.name, this);
}
}
foo3.fn();
}
var foo1 = new Foo1();
foo1.fn();
foo2.fn();
test();
test2();
This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 4 years ago.
So, I have 3 functions as follows:
function a() {
arguments[0]();
}
function b(fn) {
fn();
}
function c() {
console.log(this);
}
Now, consider the outputs:
a(c) // Arguments
b(c) // Window
a(() => {console.log(this}) // Window
b(() => {console.log(this)}) // Window
Why does a(c) output Arguments while it is window (considering non-strict) in all other cases?
In JavaScript this usually refers to the object from which the function was called (unless it's an arrow function). So for example if we do something like this:
var obj = { fun: function() { console.log(this); } }
var obj1 = { fun: obj.fun, otherProperty: 123 }
obj.fun(); // equivalent to obj["fun"]()
obj1.fun(); // equivalent to obj1["fun"]()
We will find out that in the first call this refers to obj and in the second it refers to obj1 even though it's the same function.
Now, the arguments variable is an object which stores all the arguments which were passed to the function. If an argument was a function and you access it through the arguments object, it becomes a "parent" object from which the function was called and it becomes the new this in the function's execution context. You can consider your case to be equal to something like this:
function c() {
console.log(this);
}
var arguments = { "0" : c }
arguments["0"]() // will log the arguments object
In your second invocation (b(c)) the function passed as an argument is called directly inside the parent function, without accessing it through a proxy object - in that case this will be copied from the parent execution scope, which is window.
In the third and fourth example both functions are defined using the arrow function, which saves the value of this from the context in which they were created and they prevent this value from being changed.
More about arrow functions: Arrow functions
Given the following code:
const outter = {
inner: {
laughter: "hahaha",
laugh: () => {
console.log(this) //`this` is window
}
}
}
const x = {
test: function () {
const laugh = outter.inner.laugh
console.log(this) //`this` is x
laugh()
}
}
x.test()
I would expect the this inside of the laugh method to be equal to x - because we're invoking laugh from x
In the scope where we invoke laugh, this is equal to x - so it's strange that this changes in the arrow method, which should follow lexical scope.
(note, even if we change laugh to a normal function, non-arrow, this is still Window - but that makes sense)
Can anyone explain why this inside of laugh is Window?
Thanks
According Jason Orendorff, the guy who implemented arrow functions for Firefox, wrote the following (here):
Arrow functions do not have their own this value. The value of this inside an arrow function is always inherited from the enclosing scope.
The arrow function is not assigned when invoked, rather, when it's defined.
In your example, the arrow function of the laugh property will be bound to the this in the scope it was defined in, which in your example is window.
Update
The OP remarked in the comments that since the arrow function is found inside an inner property of the outter [sic] object, it should pick up the scope of that object. Superficially, this is the way it should be.
The caveat is that when creating objects, JS has to assign the property values from the inside out. In other words, the inner object literal is created first, at a time when the context of outter doesn't even exist yet!. And, therefore, since arrow functions get bound at the time of creation, the function for the outter.inner.laugh method is being bound with the context that it is found in; at the time of creating outter.inner, that would be window.
Arrow Functions:
Do not have this.
Do not have arguments.
Can’t be called with new.
They also don’t have super.
Arrow functions have no “this”
If this is accessed, it is taken from the outside.
const outter = {
inner: {
laughter: "hahaha",
laugh: () => {
console.log(this) // the outer `this` is window.
}
}
}
Read more here.
This question already has answers here:
In Javascript, why is the "this" operator inconsistent?
(8 answers)
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 4 years ago.
I have this code:
let bar = () => {
let x = 5;
console.log(this.x)
}
bar();
It does not work. I also have this code:
let bar = () => {
this.x = 5;
console.log(this.x)
}
bar();
It does work. I want to make sure I understand why. As I understand it, simply declaring a variable within a function does not make it a value on the function object. Only when declaring this.___ = ____ does it actually become a value on the object.
...is that right?
There are two types of functions in JavaScript with respect to this: arrow functions and non-arrow functions.
function () {}
For non-arrow functions, you can think of this as just another parameter. Where a typical parameter would be set by passing an argument:
function foo(x) {
return x;
}
foo(1); // returns 1
the this parameter is set by how the function is called:
function foo() {
return this;
}
var obj = { foo: foo };
foo(); // returns undefined, because it’s not one of the following
// special forms
obj.foo(); // returns obj, because the function was called with dot notation
obj['foo'](); // returns obj, because bracket notation and dot notation
// work the same
foo.call(1); // returns 1, because a function’s `call` method
// sets `this` explicitly
new foo(); // returns a new object of type `foo`‽ read up!
Every non-arrow function has this implicit parameter called this. The top scope, outside any function, also has a this. It can be a few different things, depending on your environment; you can safely ignore it.
() => {}
Arrow functions don’t have the implicit this parameter. They use the this from their containing scope, like any other variable. In other words, in complete opposition to non-arrow functions, how they’re called doesn’t matter at all; it’s about where the () => { … } is located.
// `this` outside `foo`…
const foo = () => {
// is the same as `this` inside `foo`. always.
return this;
};
Now, tying it all together, your arrow functions are in the top scope, outside of any other function. That means they have whatever this was in the top scope. If that isn’t undefined, you can set values on it, like you’re doing with this.x = 5; in an arrow function. It’s the same this every time, though, and it’s certainly not referring to “the function object”.
As for the first example: declaring variables, like with let x = 5;, has nothing to do with this at all.
It seems to me that, in ES6, the following two functions are very nearly identical:
function () {
return this;
}.bind(this);
() => {
return this;
};
The end result seems the same: arrow functions produce a JavaScript function object with their this context bound to the same value as the this where they are created.
Obviously, in the general sense, Function.prototype.bind is more flexible than arrow functions: it can bind to values other than the local this, and it can bind any function's this at any point in time, potentially long after it is initially created. However, I'm not asking how bind itself is different from arrow functions, I'm asking how arrow functions differ from immediately calling bind with this.
Are there any differences between the two constructs in ES6?
There are no (significant) differences.
Well, okay, that's a little premature. There are three tiny differences unique to arrow functions.
Arrow functions cannot be used with new.
This means, of course, that they do not have a prototype property and cannot be used to create an object with the classically-inspired syntax.
new (() => {}) // TypeError: () => {} is not a constructor
This is probably for the best, though—the way new works would not make much sense with bound functions.
Arrow functions do not have access to the special arguments object that ordinary JavaScript functions have access to.
(() => arguments)(1, 2, 3) // ReferenceError: arguments is not defined
This one is probably a little bit more of a gotcha. Presumably this is to remove one of JavaScript's other oddities. The arguments object is its own special beast, and it has strange behavior, so it's not surprising that it was tossed.
Instead, ES6 has splats that can accomplish the same thing without any magic hidden variables:
((...args) => args)(1, 2, 3) // [1, 2, 3]
Arrow functions do not have their own new.target property, they use the new.target of their enclosing function, if it exists.
This is consistent with the other changes to remove "magically" introduced values for arrow functions. This particular change is especially obvious, considering arrow functions can't be used with new anyway, as mentioned above.
Otherwise, arrows are just like bound functions, semantically. It's possible for arrows to be more performant, since they don't have to carry around the extra baggage and since they don't need to be converted from ordinary functions first, but they're behaviorally exactly the same.
There are a few differences:
Arrow functions cannot be constructed. While both arrow functions and bound functions both don't have a .prototype property, the former do throw an exception when called with new while the latter just ignore the bound value and call their target function as a constructor (with the partially applied bound arguments, though) on the new instance.
function F() {}
var f = () => {},
boundF = F.bind({});
console.log(new boundF(), new boundF instanceof F) // {}, true
console.log(new f) // TypeError
Arrow functions do have lexical arguments, new.target and super as well (not only lexical this). A call to an arrow function does not initialise any of those, they are just inherited from the function the arrow function was defined in. In a bound function, they just refer to the respective values of the target function.
Arrow functions don't actually bind a this value. Rather, they don't have one, and when you use this it is looked up like a variable name in the lexical scope. This does allow you to lazily define an arrow function while this is not yet available:
class X extends Object {
constructor() {
var f = () => this, // works
boundF = function(){ return this; }.bind(this);
// ^^^^ ReferenceError
super(); // initialises `this`
console.log(f(), f() == this); // {}, true
}
}
new X;
Arrow functions cannot be generator functions (though they can return generators). You can use .bind() on a generator function, yet there is no way to express this using an arrow function.
Here is one more subtle difference:
Arrow functions can return a value without using the 'return' keyword, by omitting the {} braces following the => immediately.
var f=x=>x; console.log(f(3)); // 3
var g=x=>{x}; console.log(g(3)); // undefined
var h=function(x){x}; console.log(h(3)); // undefined
var i=x=>{a:1}; console.log(i(3)); // undefined
var j=x=>({a:1}); console.log(j(3)); // {a:1}