Value of this inside object method? [duplicate] - javascript

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 6 years ago.
I very confusing about the value of this at the moment of an invocation function using arrow functions. Let's take my example:
var obj = {
property: 5,
func1: function () {
console.log(this.property);
},
func2: () => {
console.log(this.property);
}
}
When i put this code on the browser console, an interesting thing happens, func1() will output 5 as expected *, but when i run func2 i got undefined. What is going on here? Why the value of this inside func2 makes reference to the global object(Window in this case).
I think i expect that output, because it is how it works, thats the reason why Alan and slevetman explains here and here respectively. But according to the Jason's explanation
Arrow functions do not have their own this value. The value of this inside an arrow function is always inherited from the enclosing scope.
So, why the value of this inside func2 is not inheriting the value of his enclosing scope obj?

So, why the value of this inside func2 is not inheriting the value of his enclosing scope obj?
The obj here is not the "enclosing" scope. The scope that you are defining the obj in is the "enclosing" scope.
Consider this example:
var obj = {
property: 5,
func1: function () {
let func2 = () => {
console.log(this.property);
}
func2();
},
}
obj.func1(); // logs 5
obj.func1.call({
property: 6
}) // logs 6
When the inner func2 is called, the this keyword refers to the obj as this in the wrapper func1 function refers to the obj and the func2 inherits the this value. The inner arrow function does not bind it's own this value.

The this in func2 is inheriting the value of the scope of the function itself, no more. To make it work, you'll have to make something like that :
var obj = {
property: 5,
func1: function () {
console.log(this.property); // shows 5
},
func2: () => {
console.log(this.property); // shows undefined
this.property = 6;
console.log(this.property); // shows 6
}
}

Related

What does "This" refer to in this Javascript code? [duplicate]

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 4 years ago.
I'm learning Javascript, and I'm a little confused about the "this" keyword. I understand it refers to the specific instance of an object if it's called (i.e. if fido = new Dog("Fido"), then this.method will refer to the specific object it's called on).
However, I was doing a problem off of Javascript.info, and they had the following solution for implementing a Delay wrapper to the Function prototype:
Function.prototype.defer = function(ms) {
let f = this; //*****
return function(...args) {
setTimeout(() => f.apply(this, args), ms); //****
}
};
// check it
function f(a, b) {
alert(a + b);
}
f.defer(1000)(1, 2); // shows 3 after 1 sec
I'm confused about the use of "this" in the solution. In the first call, (let f = this), it sets f to the specific call of the function. However, 2 lines after, they call f.apply(this, args). I'm confused why they used both the variable f, as well as the actual "this" keyword here... what is the difference in what they refer to?
Thanks!
Edit: The exercise says it's not good practice to change the prototype, but it's there just to test your understanding
Edit2: I've also tried using console.log(this), and it shows up undefined. I'm curious why I need it at all (inputting " " instead of "this" actually yields the same result, which is why I am confused)
As other comments and answers have pointed out, there are several good articles out there that can explain in greater details the "this" keyword. But to answer your question the first "this"(let f = this) is a pointer to the function f, while the second "this"(f.apply(this, args)) is a pointer to the window object because setTimeout is a function of the window object.
I'll annotate the code below:
Function.prototype.defer = function(ms) {
// The function was called via a reference to a function, so the "this"
// pointer being captured in "f" will refer to the function that was to be
// deferred;
let f = this;
return function(...args) {
// The "this" pointer here refers to the global window object, since
// the anonymous function returned above didn't explicitly specify
// a this pointer via bind or other means
console.log(this);
setTimeout(() => {
// Because of the use of an arrow function, the "this" pointer here
// refers to whatever is the "this" pointer in the containing block
// Remember, f refers to the original function, so we're invoking it
// here
f.apply(this, args)
}, ms);
}
};
Essentially, it's because 'this' changes very rapidly. Inside setTimeout it will be different to outside. You use f (though most would use 'self' or similar) to lock down 'this' at a specific point at execution.
How to access the correct `this` inside a callback? is pretty thorough.
As defer returns a function, this in f.apply(this, args), ms) would refer to whichever scope the returned function is called at.
Example:
function First () {
this.name = 'First';
}
First.prototype.defer = function(ms) {
const f = this;
return function() {
setTimeout(() => {
console.log('Names => ', f.name, this.name);
}, ms);
}
}
const first = new First();
function Second() {
this.name = 'Second';
}
const second = new Second();
second.deferby1000 = first.defer(1000);
second.deferby1000(); // Names => "First" "Second"

JavaScript - this inside of timeout with arrow functions [duplicate]

This question already has answers here:
What does "this" refer to in arrow functions in ES6?
(10 answers)
Closed 6 years ago.
Why isn't this inside of the setTimeout equal to the object that invoked the render function when using arrow functions?
class X {
constructor(config) {
this.data = config.data;
this.render_ = config.render;
}
render() {
this.render_(this.data);
}
}
var x = new X({
data: [1, 2, 3],
render: (data) => {
setTimeout(() => {
console.log(this);
}, 200);
}
});
x.render();
Read the part of the arrow function documentation that says "Arrow functions used as methods"
in summary: arrow functions just simply do not bind this or their own version of this, but rather references the global Window object.
Because arrow functions are lexically bound. That means they take on the value of "this" at the time of declaration. They are not affected by other means of modifying the this value, including being called as a method or functions like bind, apply and call.
function F() {
this.type = 'F';
this.logTypeExpression = function() {
console.log(this.type);
};
this.logTypeArrow = () => {
console.log(this.type);
};
}
function G() {
this.type = 'G';
}
var f = new F();
var g = new G();
f.logTypeExpression(); // F
f.logTypeArrow(); // F
// Now lets give these functions to G
g.logTypeExpression = f.logTypeExpression;
g.logTypeArrow = f.logTypeArrow;
g.logTypeExpression(); // G
g.logTypeArrow(); // F(!) (That's because `this` was assigned by the arrow function)
At the time that the arrow function is created, this isn't bound to any object, so it still refers to window. Maybe you want to try console.log(x); if you want to refer to that specific instance?
The code below only holds a reference to the function you created using an object literal syntax.
this.render_ = config.render;
Using bind(this) will tell the function to use the parameter object as the this reference when calling the function in the instance of your X object.
class X {
constructor(config) {
this.data = config.data;
this.render_ = config.render.bind(this);
}
render() {
this.render_(this.data);
}
}
Also, it does not matter if it's an arrow function or a regular function expression in your code snippet.

Why does 'this' return 'undefined' when referred in an arrow function but doesn't when called on an anonymous function? [duplicate]

This question already has an answer here:
this is undefined inside arrow function
(1 answer)
Closed 6 years ago.
I'm working with node.js v6.7.0 and while declaring an object with a reference to 'this' it returns undefined if it's inside an arrow function but when it's inside a regular anonymous function it returns the object itself (which is what I want)
eg
let obj = {
key: 'val',
getScopeWithArrow: () => {return this;}, //returns undefined
getScopeWithAnonymous: function() {return this;} //returns the object properly
}
Because arrow functions don't have their own this, they close over the this of the calling context. But non-arrow functions, if they're not bound, take this based on how they're called. I assume you're calling these functions like this:
obj.getScopeWithArrow();
obj.getScopeWithAnonymous();
In the first case, again, the arrow function doesn't get its own this so it doesn't matter how you're calling it. In the second case, it does matter, and calling it like that makes this within the call refer to the same object obj refers to.
Separately: In your example, you must be in strict mode, because this can only be undefined in strict mode.
Separately 2: With regard to your method names: this and "scope" have very, very little to do with one another.
Some examples:
function showThis(label, t) {
if (t === window) {
console.log(label, "(global object)");
} else {
console.log(label, t);
}
}
// Loose mode by default in a non-module script element
let obj = {
arrow: () => {
showThis("arrow says ", this);
},
normal: function() {
showThis("normal says ", this);
}
};
obj.arrow(); // global object (window on browsers)
obj.normal(); // obj
function foo() {
// Here, we're in strict mode
"use strict";
let obj = {
arrow: () => {
showThis("arrow says ", this);
},
normal: function() {
showThis("normal says ", this);
}
};
obj.arrow(); // undefined
obj.normal(); // obj
}
foo();
According to developer.mozilla.org (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
No binding of this
Until arrow functions, every new function defined its own this value (a new object in case of a constructor, undefined in strict mode function calls, the context object if the function is called as an "object method", etc.). This proved to be annoying with an object-oriented style of programming.
BUT
If the goal is to avoid writing function, you can avoid using the colon and declare your method with the new ECMA6 object function declaration syntax.
let obj = {
key: 'val',
getScopeWithParens() {return this;}, //returns object
getScopeWithAnonymous: function() {return this;} //returns the object properly
}
console.log(obj.getScopeWithAnonymous());
console.log(obj.getScopeWithParens());

Why can't I access `this` within an arrow function? [duplicate]

This question already has answers here:
What does "this" refer to in arrow functions in ES6?
(10 answers)
Closed 7 years ago.
This code below should work as expected, and log "meow", here an example.
function Cat () {
this.animalNoise = 'meow'
}
Cat.prototype.sound = () => {
console.log(this.animalNoise)
}
let cat = new Cat()
cat.sound()
It doesn't work, this error appears TypeError: Cannot read property 'animalNoise' of undefined and when you convert the arrow function to an actual function declaration it works. It seems like with the arrow function, I no longer have access to this. What's going on here?
To be clear, the above code does not work where the following does, and I'm very curious why.
function Cat () {
this.animalNoise = 'meow'
}
Cat.prototype.sound = function() {
console.log(this.animalNoise)
}
let cat = new Cat()
cat.sound()
Arrow functions perform lexical binding and uses the surrounding scope as the scope of this. For example, imagine (for some weird reason) you define Cat inside of a Dog constructor.
function Dog() {
// do dog like things
function Cat() { ... }
Cat.prototype.sound = () => {
// this == instance of Dog!
};
}
So whatever the surrounding scope is becomes the scope of an arrow function.

Why nested local function binds `this` to window instead of the parent

I was reading some documentation about javascript and stumbled upon the following code example:
var o = {
value: 1,
outer: function () {
var inner = function () {
console.log(this); //bound to global object
};
inner();
}
};
o.outer();
It outputs window.
I cannot figure out why is the this keyword bound to the global object (window) instead of the parent object (outer).
If you want to access outer from inner's scope, you have to pass the outer's this (which is just like passing outer itself) to its local inner function as an argument. So, as expected:
var o = {
value: 1,
outer: function () {
var inner = function (that) {
console.log(that); //bound to global object
};
inner(this);
}
};
o.outer();
outputs outer.
Isn't it a bit of a nonsense that in outer's scope this is bound to the object itself (i.e. outer), while in the inner's scope, which is local to outer, this is re-bound to the global object (i.e. it overrides outer's binding)?
The ECMAScript specs states that when entering the execution context for function code if the «caller provided thisArg» is either null or undefined, then this is bound to the global object.
But the following:
var o = {
outer: function () {
var inner = function () {
console.log('caller is ' + arguments.callee.caller);
};
inner();
}
}
outputs the object outer itself:
caller is function () {
var inner = function () {
console.log('caller is ' + arguments.callee.caller);
};
inner();
}
On a side, but probably relevant, note:
In strict mode the first code snippet outputs undefined instead of window.
This is because this is set when the function is run, not when it's defined.
For example:
var o = {
func: function(){
console.log(this);
}
};
When you call o.func(), you are doing so in the context o, so it works as expected.
Now let's say you do this:
var f = o.func;
f();
This will not work as expected. This is because when you call f(), it doesn't have any context attached to it, so this will be window.
You can fix this by using .call to change the value of this.
var f = o.func;
f.call(o); // sets `this` to `o` when calling it
That's just how it the language works.
Every time a function is called, this will be reset. In a nested (inner) function it does not inherit the value from the enclosing scope the way other (explicitly declared) variables are.
By default this will be set to window, unless the function is invoked as:
myObj.func(arg1, ...) or
func.call(myObj, arg1, ...) or
func.apply(myObj, [arg1, ...])
in which case this will be equal to myObj
A function called any other way, even if it was originally defined as a property of an object (i.e. var func = myObj.func; func() will use window.
There's also a utility function called .bind which wraps a function reference in such a way that you can provide a specific value which will always be used as this:
var myFunc = myObj.func; // obtain reference to func
var bound = myFunc.bind(someOtherObj); // bind it to "someOtherObj"
bound(); // this === someOtherObj
bound.call(myObj) // this still === someOtherObj

Categories

Resources