Last active
September 10, 2020 07:00
-
-
Save connorrose/22252565f4daf087150134e0a08c6b8d to your computer and use it in GitHub Desktop.
This Binding of Arrow Functions vs normal Function Expressions in various contexts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// GLOBAL SCOPE | |
const foo = () => this; | |
const bar = function() {return this}; | |
const baz = globalThis; | |
const thud = this; | |
console.log('globalThis : this in global scope => ', baz === thud); // false | |
console.log('Arrow this : this in global => ', foo() === thud); // true | |
console.log('Function this : globalThis => ', bar() === baz); // true | |
-------------------------- | |
// DEFINED IN GLOBAL SCOPE | |
function normalGlobal() { | |
// this => Global object (defaults to globalThis when no invoking object) | |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis | |
} | |
const arrowGlobal = () => { | |
// this => {} [empty object] (this-value on Global object) | |
} | |
---------------------------- | |
// DEFINED IN FUNCTION SCOPE | |
function wrapperInGlobal() { | |
function normalWrapped() {}; | |
const arrowWrapped = () => {}; | |
normalWrapped(); // this => Global object (default behavior) | |
arrowWrapped(); // this => Global object (inherits from wrappedInGlobal, which defaulted to globalThis) | |
} | |
wrapperInGlobal(); | |
----------------------------------------------- | |
// DEFINED AS OBJECT METHODS (OBJECT IN GLOBAL) | |
const demoObject = { | |
demoProperty: true, | |
normalMethod: function() {}, | |
arrowMethod: () => {} | |
} | |
demoObject.normalMethod(); // this => demoObject (bound at call time to invoking object) | |
demoObject.arrowMethod(); // this => {} [empty object] (bound at definition, which was in Global scope, so empty object) | |
-------------------------------------------- | |
// DEFINED AS OBJECT METHODS WITHIN FUNCTION | |
function wrapperInGlobal() { | |
const demoObject = { | |
demoProperty: true, | |
normalMethod: function() {}, | |
arrowMethod: () => {} | |
} | |
demoObject.normalMethod(); // this => demoObject (still bound at call time to invoking object | |
demoObject.arrowMethod(); // this => Global object, inherited from wrapperInGlobal | |
} | |
------------------- | |
// NESTED FUNCTIONS | |
function wrapperInGlobal() { | |
const demoObject = { | |
normalMethod: function() { | |
console.log('LOG 1: ' + this); | |
function nestedNormal() { | |
console.log('LOG 2: ' + this); | |
} | |
const nestedArrow = () => { | |
console.log('LOG 3: ' + this); | |
} | |
nestedNormal(); | |
nestedArrow(); | |
} | |
} | |
demoObject.normalMethod(); | |
} | |
wrapperInGlobal(); | |
// LOG 1: demoObject => normalMethod is bound to the object that invoked it | |
// LOG 2: Global object => default this value for a normal function call without an invoking object, regardless of enclosing scope | |
// LOG 3: demoObject => nestedArrow inherits it's this value from the surrounding scope, which is normalMethod | |
------------------------------------------------- | |
// DEFINED GLOBALLY / CALLED IN FUNCTION / METHOD | |
const arrowGlobal = () => { | |
console.log('Arrow: ' + this) | |
} | |
const normalGlobal = function() { | |
console.log('Normal: ' + this) | |
} | |
function wrapperInGlobal() { | |
const wrappedArrow = () => { | |
console.log(`Wrapped: ` + this) | |
} | |
const demoObject = { | |
demoProp: true, | |
normalMethod: function() { | |
console.log('Method: ' + this) | |
arrowGlobal(); | |
normalGlobal(); | |
} | |
} | |
demoObject.normalMethod(); | |
} | |
wrapperInGlobal(); | |
// Arrow: {} => empty object retained from definition in global | |
// Wrapped: Global object => inherited from wrapper function | |
// Normal: Global Object => default w/ no invoking object | |
// Method: demoObject => invoking object | |
// NOTE: Arrow / Wrapped do NOT inherit demoObject as this-value despite being invoked within normalMethod | |
---------------------- | |
// *** SET TIMEOUT *** | |
// Global | |
function normalGlobal() { | |
console.log(`NORMAL GLOBAL: ${JSON.stringify(this)}`); | |
} | |
setTimeout(normalGlobal, 0); // this => some weird timer object | |
setTimeout(function () { | |
console.log(`NORMAL ANON: ${JSON.stringify(this)}`); | |
}, 0); // this => same weird timer object | |
const arrowGlobal = () => { | |
console.log(`ARROW GLOBAL: ${JSON.stringify(this)}`); | |
}; | |
setTimeout(arrowGlobal, 0); // this => {} (empty object) | |
setTimeout(() => { | |
console.log(`ARROW ANON: ${JSON.stringify(this)}`); | |
}, 0); // this => {} (empty object) | |
// As Object Method | |
const demoObject = { | |
demoProp: true, | |
normalMethod() { | |
console.log(`normalMethod: ${JSON.stringify(this)}`); | |
}, | |
arrowMethod: () => { | |
console.log(`normalMethod: ${JSON.stringify(this)}`); | |
}, | |
}; | |
setTimeout(demoObject.normalMethod, 0); // this => timer object [NOT demoObject as would be without setTimeout] | |
setTimeout(demoObject.arrowMethod, 0); // this => {} [empty object from Global] | |
// Within Object Method | |
const demoObject = { | |
demoProp: true, | |
normalMethod() { | |
function normalGlobal() { | |
console.log(`NORMAL GLOBAL: ${JSON.stringify(this)}`); | |
} | |
setTimeout(normalGlobal, 0); | |
setTimeout(function () { | |
console.log(`NORMAL ANON: ${JSON.stringify(this)}`); | |
}, 0); | |
const arrowGlobal = () => { | |
console.log(`ARROW GLOBAL: ${JSON.stringify(this)}`); | |
}; | |
setTimeout(arrowGlobal, 0); | |
setTimeout(() => { | |
console.log(`ARROW ANON: ${JSON.stringify(this)}`); | |
}, 0); | |
}, | |
}; | |
demoObject.normalMethod(); | |
// both "normal" functions still have a "this" bound to the timer object | |
// both arrow functions now have a "this" bound to the demoObject, which they inherited from the normalMethod | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment