Related
I've been experimenting with ES6 for a while now, and I've just come to a slight problem.
I really like using arrow functions, and whenever I can, I use them.
However, it would appear that you can't bind them!
Here is the function:
var f = () => console.log(this);
Here is the object I want to bind the function to:
var o = {'a': 42};
And here is how I would bind f to o:
var fBound = f.bind(o);
And then I can just call fBound:
fBound();
Which will output this (the o object):
{'a': 42}
Cool! Lovely! Except that it doesn't work. Instead of outputting the o object, it outputs the window object.
So I'd like to know: can you bind arrow functions? (And if so, how?)
I've tested the code above in Google Chrome 48 and Firefox 43, and the result is the same.
You cannot rebind this in an arrow function. It will always be defined as the context in which it was defined. If you require this to be meaningful you should use a normal function.
From the ECMAScript 2015 Spec:
Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function.
To be complete, you can re-bind arrow functions, you just can't change the meaning of this.
bind still has value for function arguments:
((a, b, c) => {
console.info(a, b, c) // 1, 2, 3
}).bind(undefined, 1, 2, 3)()
Try it here:
http://jsbin.com/motihanopi/edit?js,console
From the MDN:
An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous.
This means you cannot bind a value to this like you want.
description: Stijn de Witt
You cannot use bind to change the value of this inside an arrow function. However, you can create a new regular function that does the same thing as the old arrow function and then use call or bind to re-bind this as usual.
We use an eval call here to recreate the arrow function you pass in as a normal function and then use call to invoke it with a different this:
code: me
const func = v => console.log(this);
const obj = {value: 10};
function arrowBindOld(context, fn) {
let arrowFn;
(function() {
arrowFn = eval(fn.toString());
arrowFn();
}).call(context);
}
arrowBindOld(obj, func);
update
const f = v => console.log(this, v);
const o = {value: 10};
/* new */
function arrowBind(context, fn) {
const arrowFnString = fn.toString();
return (function() {
return eval(arrowFnString);
}).call(context);
}
const fBound = arrowBind(o, f);
fBound(10);
/* use prototype */
Function.prototype.arrowBind = function(context) {
const arrowFnString = this.toString();
return (function() {
return eval(arrowFnString);
}).call(context);
}
const fBoundProto = f.arrowBind(o);
fBoundProto(20);
For years, js developers struggled with context binding, asked why this changed in javascript, so much confusion over the years due to context binding and the difference between the meaning of this in javascript and this in most of the other OOP languages.
All this leads me to ask, why, why! why would you wan't to rebind an arrow function! Those where created specially to solve all this issues and confusions and avoid having to use bind or call or whatever other way to preserve the scope of the function.
TL;DR
No, you cannot rebind arrow functions.
Short, You CANNOT bind arrow functions, but read on:
Imagine you have this arrow function below which prints this on the console:
const myFunc = ()=> console.log(this);
So the quick fix for this would be using normal function, so just change it to:
function myFunc() {console.log(this)};
Then you can bind it to any lexical environment using bind or call or apply:
const bindedFunc = myFunc.bind(this);
and call it in case of bind.
bindedFunc();
There are also ways to using eval() to do it, which strongly not recommended.
Do ES6 Arrow Functions Really Solve “this” In JavaScript
The above link explains that arrow functions this doesn't change with bind, call, apply functions.
It is explained with a very nice example.
run this in node v4 to see the "expected" behavior,
this.test = "attached to the module";
var foo = { test: "attached to an object" };
foo.method = function(name, cb){
// bind the value of "this" on the method
// to try and force it to be what you want
this[name] = cb.bind(this); };
foo.method("bar", () => { console.log(this.test); });
foo.bar();
I think this is better solution
var f = (vm=this) => console.log(vm);
I asked the same question a couple days ago.
You cannot bind a value since the this is already bound.
Binding different this scope to ES6 => function operator
Maybe this example help to you :
let bob = {
_name: "Bob",
_friends: ["stackoverflow"],
printFriends:(x)=> {
x._friends.forEach((f)=> {
console.log(x._name + " knows " + f);
});
}
}
bob.printFriends = (bob.printFriends).bind(null,bob);
bob.printFriends();
Well it's meant to be impossible to bind an object to an arrow function, never say never; I figured a hack that just might work.
function arrowToRegularFn(callback) {
let _callback = callback
const stringifiedCallback = callback.toString()
const isArrowFn = !stringifiedCallback.trim().startsWith("function")
if (isArrowFn) {
const isParamsInParantheses = stringifiedCallback.trim().startsWith("(")
const [fnParams, ...fnBody] = stringifiedCallback.split("=>")
_callback = eval("(function" + (!isParamsInParantheses ? "(" : "") + fnParams + (!isParamsInParantheses ? ")" : "") + "{" + fnBody.join("=>") + "})")
}
return _callback
}
// test cases
// our object to bind
const quiver = { score: 0 }
let arrow, regular;
// test - 1
arrow = () => this.score++
regular = arrowToRegularFn(arrow).bind(quiver)
regular()
console.log(quiver.score) // 1
// test - 2
arrow = (x, y) => this.score = x + y
regular = arrowToRegularFn(arrow).bind(quiver)
regular(1, 2)
console.log(quiver.score) // 3
// test - 3
arrow = (x, y) => { this.score = x + y }
regular = arrowToRegularFn(arrow).bind(quiver)
regular(3, 4)
console.log(quiver.score) // 7
// test - 4
arrow = function(x, y) { this.score = x + y }
regular = arrowToRegularFn(arrow).bind(quiver)
regular(5, 6)
console.log(quiver.score) // 11
Normal bind:
tag.on("Initialized", function(tag) {
nodeValueChanged(tag, currentNode)
}.bind(currentNode))
Arrow function bind:
tag.on("Initialized", (tag => { nodeValueChanged(tag, currentNode) }).bind(currentNode))
Arrow functions always have this based on its closest non-arrow function irrespective of where it is called. If there is no non-arrow parent it always refers to the global object.
While you are calling the arrow function using call/bind/apply it's doesn't point to the object which you are passing.
var obj = {a:1};
var add=(b)=>{
return this.a + b;
// basically here this.a will be undefined as it's trying to find in one level up which is parents of this function that is window.
}
add.call(obj,2);
So that's why passing object doesn't work in arrow function.
I've read in several places that the key difference is that this is lexically bound in arrow functions. That's all well and good, but I don't actually know what that means.
I know it means it's unique within the confines of the braces defining the function's body, but I couldn't actually tell you the output of the following code, because I have no idea what this is referring to, unless it's referring to the fat arrow function itself....which doesn't seem useful.
var testFunction = () => {
console.log(this)
};
testFunction();
Arrow functions capture the this value of the enclosing context
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| properly refers to the person object
}, 1000);
}
var p = new Person();
So, to directly answer your question, this inside your arrow function would have the same value as it did right before the arrow function was assigned.
In order to provide the big picture I'm going to explain both, dynamic and lexical binding.
Dynamic Name Binding
this refers to the object the method is called on. This is a regularly to be read sentence on SO. But it is still only a phrase, pretty abstract. Is there a corresponding code pattern to this sentence?
Yes there is:
const o = {
m() { console.log(this) }
}
// the important patterns: applying methods
o.m(); // logs o
o["m"](); // logs o
m is a method because it relies on this. o.m() or o["m"]() means m is applied to o. These patterns are the Javascript translation to our famous phrase.
There is another important code pattern that you should pay attention to:
"use strict";
const o = {
m() { console.log(this) }
}
// m is passed to f as a callback
function f(m) { m() }
// another important pattern: passing methods
f(o.m); // logs undefined
f(o["m"]); // logs undefined
It is very similar to the previous pattern, only the parenthesis are missing. But the consequences are considerable: When you pass m to the function f, you pull outm of its object/context o. It is uprooted now and this refers to nothing (strict mode assumed).
Lexical (or Static) Name Binding
Arrow functions don't have their own this/super/arguments binding. They inherit them from their parent lexical scope:
const toString = Object.prototype.toString;
const o = {
foo: () => console.log("window", toString.call(this)),
bar() {
const baz = () => console.log("o", toString.call(this));
baz();
}
}
o.foo() // logs window [object Window]
o.bar() // logs o [object Object]
Apart from the global scope (Window in browsers) only functions are able to form a scope in Javascript (and {} blocks in ES2015). When the o.foo arrow function is called there is no surrounding function from which baz could inherit its this. Consequently it captures the this binding of the global scope which is bound to the Window object.
When baz is invoked by o.bar, the arrow function is surrounded by o.bar (o.bar forms its parent lexical scope) and can inherit o.bar's this binding. o.bar was called on o and thus its this is bound to o.
Hope this code show could give you clearer idea. Basically, 'this' in arrow function is the current context version of 'this'. See the code:
// 'this' in normal function & arrow function
var this1 = {
number: 123,
logFunction: function () { console.log(this); },
logArrow: () => console.log(this)
};
this1.logFunction(); // Object { number: 123}
this1.logArrow(); // Window
Arrow function this is pointing to the surrounding parent in Es6, means it doesn't scope like anonymous functions in ES5...
It's very useful way to avoid assigning var self to this which is widely used in ES5...
Look at the example below, assigning a function inside an object:
var checkThis = {
normalFunction: function () { console.log(this); },
arrowFunction: () => console.log(this)
};
checkThis.normalFunction(); //Object {}
checkThis.arrowFunction(); //Window {external: Object, chrome: Object, document: document, tmpDebug: "", j: 0…}
You can try to understand it by following the way below
// whatever here it is, function or fat arrow or literally object declare
// in short, a pair of curly braces should be appeared here, eg:
function f() {
// the 'this' here is the 'this' in fat arrow function below, they are
// bind together right here
// if 'this' is meaningful here, eg. this === awesomeObject is true
console.log(this) // [object awesomeObject]
let a = (...param) => {
// 'this is meaningful here too.
console.log(this) // [object awesomeObject]
}
so 'this' in fat arrow function is not bound, means you can not make anything bind to 'this' here, .apply won't, .call won't, .bind won't. 'this' in fat arrow function is bound when you write down the code text in your text editor. 'this' in fat arrow function is literally meaningful here. What your code write here in text editor is what your app run there in repl. What 'this' bound in fat arror will never change unless you change it in text editor.
Sorry for my pool English...
Arrow function never binds with this keyword
var env = "globalOutside";
var checkThis = {env: "insideNewObject", arrowFunc: () => {
console.log("environment: ", this.env);
} }
checkThis.arrowFunc() // expected answer is environment: globalOutside
// Now General function
var env = "globalOutside";
var checkThis = {env: "insideNewObject", generalFunc: function() {
console.log("environment: ", this.env);
} }
checkThis.generalFunc() // expected answer is enviroment: insideNewObject
// Hence proving that arrow function never binds with 'this'
this will always refer to the global object when used inside an arrow function. Use the regular function declaration to refer to the local object. Also, you can use the object name as the context (object.method, not this.method) for it to refer to the local object instead of the global(window).
In another example, if you click the age button below
<script>
var person = {
firstName: 'John',
surname: 'Jones',
dob: new Date('1990-01-01'),
isMarried: false,
age: function() {
return new Date().getFullYear() - this.dob.getFullYear();
}
};
var person2 = {
firstName: 'John',
surname: 'Jones',
dob: new Date('1990-01-01'),
isMarried: false,
age: () => {
return new Date().getFullYear() - this.dob.getFullYear();
}
};
</script>
<input type=button onClick="alert(person2.age());" value="Age">
it will throw an exception like this
×JavaScript error: Uncaught TypeError: Cannot read property
'getFullYear' of undefined on line 18
But if you change person2's this line
return new Date().getFullYear() - this.dob.getFullYear();
to
return new Date().getFullYear() - person2.dob.getFullYear();
it will work because this scope has changed in person2
Differences between arrow functions to regular functions: (taken from w3schools)
With arrow functions there are no binding of this.
In regular functions the this keyword represented the object that called the function, which could be the window, the document, a button or whatever.
With arrow functions the this keyword always represents the object that defined the arrow function.
// Regular Function:
hello = function() {
document.getElementById("demo").innerHTML += this;
}
// The window object calls the function:
window.addEventListener("load", hello);
// A button object calls the function:
document.getElementById("btn").addEventListener("click", hello);
// -------------------------------------------
// Arrow function
hello2 = () => {
document.getElementById("demo2").innerHTML += this;
}
// The window object calls the function:
window.addEventListener("load", hello2);
// A button object calls the function:
document.getElementById("btn2").addEventListener("click", hello2);
<p><i>With a regular function this represents the <b>object that calls the function</b>:</i></p>
<button id='btn'>click me regular function</button>
<p id="demo">Regular function: </p>
<hr>
<p><i>With arrow function this represents the <b>owner of the function(=the window object)</b>:</i></p>
<button id='btn2'>click me arrow function</button>
<p id="demo2">Arrow function: </p>
A related issue:
Came from - Why can't I access `this` within an arrow function?
We know below from here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Does not have its own bindings to this or super, and should not be used as methods.
Arrow functions establish "this" based on the scope the Arrow function is defined within.
Had a issue with this using arrow functions, so created a class (can be function), and class variable is accessed in arrow function, thereby achieved smaller functions using arrow functions without function keyword:
class MyClassOrFunction {
values = [];
size = () => this.values.length;
isEmpty = () => this.size() === 0;
}
let obj = new MyClassOrFunction();
obj.size(); // function call here
You can also have a getter like this, that does not have function keyword, but a bit longer due to return statement, also can access other member functions:
class MyClassOrFunction {
values = [];
size = () => this.values.length;
get length() { return this.size(); }
}
let obj = new MyClassOrFunction();
obj.length; // NOTE: no function call here
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"
I've read in several places that the key difference is that this is lexically bound in arrow functions. That's all well and good, but I don't actually know what that means.
I know it means it's unique within the confines of the braces defining the function's body, but I couldn't actually tell you the output of the following code, because I have no idea what this is referring to, unless it's referring to the fat arrow function itself....which doesn't seem useful.
var testFunction = () => {
console.log(this)
};
testFunction();
Arrow functions capture the this value of the enclosing context
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| properly refers to the person object
}, 1000);
}
var p = new Person();
So, to directly answer your question, this inside your arrow function would have the same value as it did right before the arrow function was assigned.
In order to provide the big picture I'm going to explain both, dynamic and lexical binding.
Dynamic Name Binding
this refers to the object the method is called on. This is a regularly to be read sentence on SO. But it is still only a phrase, pretty abstract. Is there a corresponding code pattern to this sentence?
Yes there is:
const o = {
m() { console.log(this) }
}
// the important patterns: applying methods
o.m(); // logs o
o["m"](); // logs o
m is a method because it relies on this. o.m() or o["m"]() means m is applied to o. These patterns are the Javascript translation to our famous phrase.
There is another important code pattern that you should pay attention to:
"use strict";
const o = {
m() { console.log(this) }
}
// m is passed to f as a callback
function f(m) { m() }
// another important pattern: passing methods
f(o.m); // logs undefined
f(o["m"]); // logs undefined
It is very similar to the previous pattern, only the parenthesis are missing. But the consequences are considerable: When you pass m to the function f, you pull outm of its object/context o. It is uprooted now and this refers to nothing (strict mode assumed).
Lexical (or Static) Name Binding
Arrow functions don't have their own this/super/arguments binding. They inherit them from their parent lexical scope:
const toString = Object.prototype.toString;
const o = {
foo: () => console.log("window", toString.call(this)),
bar() {
const baz = () => console.log("o", toString.call(this));
baz();
}
}
o.foo() // logs window [object Window]
o.bar() // logs o [object Object]
Apart from the global scope (Window in browsers) only functions are able to form a scope in Javascript (and {} blocks in ES2015). When the o.foo arrow function is called there is no surrounding function from which baz could inherit its this. Consequently it captures the this binding of the global scope which is bound to the Window object.
When baz is invoked by o.bar, the arrow function is surrounded by o.bar (o.bar forms its parent lexical scope) and can inherit o.bar's this binding. o.bar was called on o and thus its this is bound to o.
Hope this code show could give you clearer idea. Basically, 'this' in arrow function is the current context version of 'this'. See the code:
// 'this' in normal function & arrow function
var this1 = {
number: 123,
logFunction: function () { console.log(this); },
logArrow: () => console.log(this)
};
this1.logFunction(); // Object { number: 123}
this1.logArrow(); // Window
Arrow function this is pointing to the surrounding parent in Es6, means it doesn't scope like anonymous functions in ES5...
It's very useful way to avoid assigning var self to this which is widely used in ES5...
Look at the example below, assigning a function inside an object:
var checkThis = {
normalFunction: function () { console.log(this); },
arrowFunction: () => console.log(this)
};
checkThis.normalFunction(); //Object {}
checkThis.arrowFunction(); //Window {external: Object, chrome: Object, document: document, tmpDebug: "", j: 0…}
You can try to understand it by following the way below
// whatever here it is, function or fat arrow or literally object declare
// in short, a pair of curly braces should be appeared here, eg:
function f() {
// the 'this' here is the 'this' in fat arrow function below, they are
// bind together right here
// if 'this' is meaningful here, eg. this === awesomeObject is true
console.log(this) // [object awesomeObject]
let a = (...param) => {
// 'this is meaningful here too.
console.log(this) // [object awesomeObject]
}
so 'this' in fat arrow function is not bound, means you can not make anything bind to 'this' here, .apply won't, .call won't, .bind won't. 'this' in fat arrow function is bound when you write down the code text in your text editor. 'this' in fat arrow function is literally meaningful here. What your code write here in text editor is what your app run there in repl. What 'this' bound in fat arror will never change unless you change it in text editor.
Sorry for my pool English...
Arrow function never binds with this keyword
var env = "globalOutside";
var checkThis = {env: "insideNewObject", arrowFunc: () => {
console.log("environment: ", this.env);
} }
checkThis.arrowFunc() // expected answer is environment: globalOutside
// Now General function
var env = "globalOutside";
var checkThis = {env: "insideNewObject", generalFunc: function() {
console.log("environment: ", this.env);
} }
checkThis.generalFunc() // expected answer is enviroment: insideNewObject
// Hence proving that arrow function never binds with 'this'
this will always refer to the global object when used inside an arrow function. Use the regular function declaration to refer to the local object. Also, you can use the object name as the context (object.method, not this.method) for it to refer to the local object instead of the global(window).
In another example, if you click the age button below
<script>
var person = {
firstName: 'John',
surname: 'Jones',
dob: new Date('1990-01-01'),
isMarried: false,
age: function() {
return new Date().getFullYear() - this.dob.getFullYear();
}
};
var person2 = {
firstName: 'John',
surname: 'Jones',
dob: new Date('1990-01-01'),
isMarried: false,
age: () => {
return new Date().getFullYear() - this.dob.getFullYear();
}
};
</script>
<input type=button onClick="alert(person2.age());" value="Age">
it will throw an exception like this
×JavaScript error: Uncaught TypeError: Cannot read property
'getFullYear' of undefined on line 18
But if you change person2's this line
return new Date().getFullYear() - this.dob.getFullYear();
to
return new Date().getFullYear() - person2.dob.getFullYear();
it will work because this scope has changed in person2
Differences between arrow functions to regular functions: (taken from w3schools)
With arrow functions there are no binding of this.
In regular functions the this keyword represented the object that called the function, which could be the window, the document, a button or whatever.
With arrow functions the this keyword always represents the object that defined the arrow function.
// Regular Function:
hello = function() {
document.getElementById("demo").innerHTML += this;
}
// The window object calls the function:
window.addEventListener("load", hello);
// A button object calls the function:
document.getElementById("btn").addEventListener("click", hello);
// -------------------------------------------
// Arrow function
hello2 = () => {
document.getElementById("demo2").innerHTML += this;
}
// The window object calls the function:
window.addEventListener("load", hello2);
// A button object calls the function:
document.getElementById("btn2").addEventListener("click", hello2);
<p><i>With a regular function this represents the <b>object that calls the function</b>:</i></p>
<button id='btn'>click me regular function</button>
<p id="demo">Regular function: </p>
<hr>
<p><i>With arrow function this represents the <b>owner of the function(=the window object)</b>:</i></p>
<button id='btn2'>click me arrow function</button>
<p id="demo2">Arrow function: </p>
A related issue:
Came from - Why can't I access `this` within an arrow function?
We know below from here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Does not have its own bindings to this or super, and should not be used as methods.
Arrow functions establish "this" based on the scope the Arrow function is defined within.
Had a issue with this using arrow functions, so created a class (can be function), and class variable is accessed in arrow function, thereby achieved smaller functions using arrow functions without function keyword:
class MyClassOrFunction {
values = [];
size = () => this.values.length;
isEmpty = () => this.size() === 0;
}
let obj = new MyClassOrFunction();
obj.size(); // function call here
You can also have a getter like this, that does not have function keyword, but a bit longer due to return statement, also can access other member functions:
class MyClassOrFunction {
values = [];
size = () => this.values.length;
get length() { return this.size(); }
}
let obj = new MyClassOrFunction();
obj.length; // NOTE: no function call here
I've read in several places that the key difference is that this is lexically bound in arrow functions. That's all well and good, but I don't actually know what that means.
I know it means it's unique within the confines of the braces defining the function's body, but I couldn't actually tell you the output of the following code, because I have no idea what this is referring to, unless it's referring to the fat arrow function itself....which doesn't seem useful.
var testFunction = () => {
console.log(this)
};
testFunction();
Arrow functions capture the this value of the enclosing context
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| properly refers to the person object
}, 1000);
}
var p = new Person();
So, to directly answer your question, this inside your arrow function would have the same value as it did right before the arrow function was assigned.
In order to provide the big picture I'm going to explain both, dynamic and lexical binding.
Dynamic Name Binding
this refers to the object the method is called on. This is a regularly to be read sentence on SO. But it is still only a phrase, pretty abstract. Is there a corresponding code pattern to this sentence?
Yes there is:
const o = {
m() { console.log(this) }
}
// the important patterns: applying methods
o.m(); // logs o
o["m"](); // logs o
m is a method because it relies on this. o.m() or o["m"]() means m is applied to o. These patterns are the Javascript translation to our famous phrase.
There is another important code pattern that you should pay attention to:
"use strict";
const o = {
m() { console.log(this) }
}
// m is passed to f as a callback
function f(m) { m() }
// another important pattern: passing methods
f(o.m); // logs undefined
f(o["m"]); // logs undefined
It is very similar to the previous pattern, only the parenthesis are missing. But the consequences are considerable: When you pass m to the function f, you pull outm of its object/context o. It is uprooted now and this refers to nothing (strict mode assumed).
Lexical (or Static) Name Binding
Arrow functions don't have their own this/super/arguments binding. They inherit them from their parent lexical scope:
const toString = Object.prototype.toString;
const o = {
foo: () => console.log("window", toString.call(this)),
bar() {
const baz = () => console.log("o", toString.call(this));
baz();
}
}
o.foo() // logs window [object Window]
o.bar() // logs o [object Object]
Apart from the global scope (Window in browsers) only functions are able to form a scope in Javascript (and {} blocks in ES2015). When the o.foo arrow function is called there is no surrounding function from which baz could inherit its this. Consequently it captures the this binding of the global scope which is bound to the Window object.
When baz is invoked by o.bar, the arrow function is surrounded by o.bar (o.bar forms its parent lexical scope) and can inherit o.bar's this binding. o.bar was called on o and thus its this is bound to o.
Hope this code show could give you clearer idea. Basically, 'this' in arrow function is the current context version of 'this'. See the code:
// 'this' in normal function & arrow function
var this1 = {
number: 123,
logFunction: function () { console.log(this); },
logArrow: () => console.log(this)
};
this1.logFunction(); // Object { number: 123}
this1.logArrow(); // Window
Arrow function this is pointing to the surrounding parent in Es6, means it doesn't scope like anonymous functions in ES5...
It's very useful way to avoid assigning var self to this which is widely used in ES5...
Look at the example below, assigning a function inside an object:
var checkThis = {
normalFunction: function () { console.log(this); },
arrowFunction: () => console.log(this)
};
checkThis.normalFunction(); //Object {}
checkThis.arrowFunction(); //Window {external: Object, chrome: Object, document: document, tmpDebug: "", j: 0…}
You can try to understand it by following the way below
// whatever here it is, function or fat arrow or literally object declare
// in short, a pair of curly braces should be appeared here, eg:
function f() {
// the 'this' here is the 'this' in fat arrow function below, they are
// bind together right here
// if 'this' is meaningful here, eg. this === awesomeObject is true
console.log(this) // [object awesomeObject]
let a = (...param) => {
// 'this is meaningful here too.
console.log(this) // [object awesomeObject]
}
so 'this' in fat arrow function is not bound, means you can not make anything bind to 'this' here, .apply won't, .call won't, .bind won't. 'this' in fat arrow function is bound when you write down the code text in your text editor. 'this' in fat arrow function is literally meaningful here. What your code write here in text editor is what your app run there in repl. What 'this' bound in fat arror will never change unless you change it in text editor.
Sorry for my pool English...
Arrow function never binds with this keyword
var env = "globalOutside";
var checkThis = {env: "insideNewObject", arrowFunc: () => {
console.log("environment: ", this.env);
} }
checkThis.arrowFunc() // expected answer is environment: globalOutside
// Now General function
var env = "globalOutside";
var checkThis = {env: "insideNewObject", generalFunc: function() {
console.log("environment: ", this.env);
} }
checkThis.generalFunc() // expected answer is enviroment: insideNewObject
// Hence proving that arrow function never binds with 'this'
this will always refer to the global object when used inside an arrow function. Use the regular function declaration to refer to the local object. Also, you can use the object name as the context (object.method, not this.method) for it to refer to the local object instead of the global(window).
In another example, if you click the age button below
<script>
var person = {
firstName: 'John',
surname: 'Jones',
dob: new Date('1990-01-01'),
isMarried: false,
age: function() {
return new Date().getFullYear() - this.dob.getFullYear();
}
};
var person2 = {
firstName: 'John',
surname: 'Jones',
dob: new Date('1990-01-01'),
isMarried: false,
age: () => {
return new Date().getFullYear() - this.dob.getFullYear();
}
};
</script>
<input type=button onClick="alert(person2.age());" value="Age">
it will throw an exception like this
×JavaScript error: Uncaught TypeError: Cannot read property
'getFullYear' of undefined on line 18
But if you change person2's this line
return new Date().getFullYear() - this.dob.getFullYear();
to
return new Date().getFullYear() - person2.dob.getFullYear();
it will work because this scope has changed in person2
Differences between arrow functions to regular functions: (taken from w3schools)
With arrow functions there are no binding of this.
In regular functions the this keyword represented the object that called the function, which could be the window, the document, a button or whatever.
With arrow functions the this keyword always represents the object that defined the arrow function.
// Regular Function:
hello = function() {
document.getElementById("demo").innerHTML += this;
}
// The window object calls the function:
window.addEventListener("load", hello);
// A button object calls the function:
document.getElementById("btn").addEventListener("click", hello);
// -------------------------------------------
// Arrow function
hello2 = () => {
document.getElementById("demo2").innerHTML += this;
}
// The window object calls the function:
window.addEventListener("load", hello2);
// A button object calls the function:
document.getElementById("btn2").addEventListener("click", hello2);
<p><i>With a regular function this represents the <b>object that calls the function</b>:</i></p>
<button id='btn'>click me regular function</button>
<p id="demo">Regular function: </p>
<hr>
<p><i>With arrow function this represents the <b>owner of the function(=the window object)</b>:</i></p>
<button id='btn2'>click me arrow function</button>
<p id="demo2">Arrow function: </p>
A related issue:
Came from - Why can't I access `this` within an arrow function?
We know below from here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Does not have its own bindings to this or super, and should not be used as methods.
Arrow functions establish "this" based on the scope the Arrow function is defined within.
Had a issue with this using arrow functions, so created a class (can be function), and class variable is accessed in arrow function, thereby achieved smaller functions using arrow functions without function keyword:
class MyClassOrFunction {
values = [];
size = () => this.values.length;
isEmpty = () => this.size() === 0;
}
let obj = new MyClassOrFunction();
obj.size(); // function call here
You can also have a getter like this, that does not have function keyword, but a bit longer due to return statement, also can access other member functions:
class MyClassOrFunction {
values = [];
size = () => this.values.length;
get length() { return this.size(); }
}
let obj = new MyClassOrFunction();
obj.length; // NOTE: no function call here