Created
May 12, 2016 05:26
-
-
Save jacklynrose/7a010d9af3795b529aa9079edca90825 to your computer and use it in GitHub Desktop.
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
// Set on window | |
this.foobar = "V1" | |
//=> (result) "V1" | |
console.log(this.foobar) | |
//=> (output) V1 | |
//=> (result) undefined | |
// Uses window | |
(() => { | |
console.log(this.foobar); | |
})() | |
//=> (output) V1 | |
//=> (result) undefined | |
// Uses window | |
(function() { console.log(this.foobar); })() | |
//=> (output) V1 | |
//=> (result) undefined | |
// Uses window | |
(function() { | |
(function() { console.log(this.foobar); })(); | |
})() | |
//=> (output) V1 | |
//=> (result) undefined | |
// Uses window | |
(function() { | |
(() => { console.log(this.foobar); })(); | |
})() | |
//=> (output) V1 | |
//=> (result) undefined | |
// Sets on window, uses that | |
(function() { | |
this.foobar = "V2"; | |
(() => { console.log(this.foobar); })(); | |
})() | |
//=> (output) V2 | |
//=> (result) undefined | |
// Resetting | |
this.foobar = "V1" | |
//=> (result) "V1" | |
// Sets and uses window | |
(function() { | |
this.foobar = "V2"; | |
(function() { console.log(this.foobar); })(); | |
})() | |
//=> (output) V2 | |
//=> (result) undefined | |
// Now where functions get weird because constructors and methods | |
function MyThing1() { | |
this.foobar = "V3"; | |
(function() { console.log(this.foobar); })(); | |
} | |
//=> (result) undefined | |
// Run the constructor and oh wait what? Uses window | |
new MyThing1(); | |
//=> (output) V2 | |
//=> (result) MyThing1 {foobar: "V3"} | |
// What if we use arrow functions? | |
function MyThing2() { | |
this.foobar = "V4"; | |
(() => { console.log(this.foobar); })(); | |
} | |
//=> (result) undefined | |
// That makes more sense now, it uses the thing above it | |
new MyThing2(); | |
//=> (output) V4 | |
//=> (result) MyThing2 {foobar: "V4"} | |
// This is how we make them act the same by binding "this" | |
function MyThing3() { | |
this.foobar = "V5"; | |
(function() { console.log(this.foobar); }).bind(this)(); | |
} | |
//=> (result) undefined | |
// Now it acts the same as the arrow function | |
new MyThing3(); | |
//=> (output) V5 | |
//=> (result) MyThing3 {foobar: "V5"} |
Another example of weirdness is if we try to force an arrow function to a context. eg:
this.foobar = 'V1';
function MyThing1() {
this.foobar = 'V2';
}
const thing = new MyThing1();
function MyThing2() {
this.foobar = 'V3';
thing.fn = function() {
console.log(this.foobar)
}
}
new MyThing2();
thing.fn()
Gives us "V2"
in the console because we assign the function within MyThing2
to the first object, thing
. But if we try to do it with arrow functions....
this.foobar = 'V1';
function MyThing1() {
this.foobar = 'V2';
}
const thing = new MyThing1();
function MyThing2() {
this.foobar = 'V3';
thing.fn = () => {
console.log(this.foobar)
}
}
new MyThing2();
thing.fn()
We get "V3". The arrow function basically says "No thanks" to your assignment and sticks with its guns. What a badass.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To expand on and explain some of the weirdness:
Calling a "Function" calls it in the context its assigned, calling an "Arrow Function" calls it in the context of the current context of the surrounding scope.
Using this lets look at some of the examples.
Following what's happening:
Window
, the default, global object, call'snew MyThing1()
the
new
keyword creates a new object and the interpreter calls the constructorMyThing1()
with the context as the new object.The first line,
this.foobar = "V3"
sets the context's valuefoobar
to"V3"
, in this case, the context is the new object, so it'sfoobar
is now "V3".The second line; we get a function declaration. The anonymous function is declared in the scope of
MyThing1
, yet it's not a method assigned to the new object that is the currently the context of the call.Side note, if we assign this anon function to the context that is currently calling
MyThing1
, we'll get the expected behaviour, eg:Anyway, back to following what's happening...
The interpreter calls the IIFE, and because the function itself is called with no context (ie,
object.fn()
orfn.call(object)
), it falls back to the default context,Window
. Thethis
inside the IIFE is nowWindow
, so it log's it'sfoobar
property, instead of thefoobar
assigned to the new object calling it, resulting in the console logging"V3"
.Now if we look at the example uses an arrow function:
If we follow it through again:
Window
, the default, global object, call'snew MyThing2()
the
new
keyword creates a new object and the interpreter calls the constructorMyThing2()
with the context as the new object.The first line,
this.foobar = "V4"
sets the context's valuefoobar
to"V4"
, in this case, the context is the new object, so it'sfoobar
is now "V4".The second line; we get an arrow function declaration. An arrow function can't be assigned to any particular context, instead it uses the context of the current scope where it was declared.
We then call the arrow function declaration, and since arrow function's use the same context as that of the current scope's context, the interpreter will pass the new object as the context!
The function then calls console.log with the
foobar
belonging to the new object, ie,"V4"
!Javascript, hey.