console.log(this) // window
function whatIsThis(){
return this
}
function variablesInThis(){
// since the value of this is the window
// all we are doing here is creating a global variable
this.person = "Elie"
}
console.log(person) // Elie
whatIsThis() // window
When 'this' is not inside of a declared object
"use strict"
console.log(this) // window
function whatIsThis(){
return this
}
function variablesInThis(){
// since we are in strict mode this is undefined
// so what happens if we add a property on undefined?
// let's see what happens when we call the function...
this.person = "Elie"
}
variablesInThis() // TypeError, can't set person on undefined!
whatIsThis() // undefined
When we enable strict mode and we are not inside a declared object
// strict mode does NOT make a difference here
var person = {
firstName: "Elie",
sayHi: function(){
return "Hi " + this.firstName
},
determineContext: function(){
return this === person
}
}
When the keyword 'this' IS inside of a declared object
person.sayHi() // "Hi Elie"
person.determineContext() // true
var person = {
firstName: "Colt",
sayHi: function(){
return "Hi " + this.firstName;
},
determineContext: function(){
return this === person;
},
dog: {
sayHello: function(){
return "Hello " + this.firstName;
},
determineContext: function(){
return this === person;
}
}
}
What happens when we have a nested object?
person.sayHi() // "Hi Colt"
person.determineContext() // true
// but what is the value of the keyword this right now?
person.dog.sayHello() // "Hello undefined"
person.dog.determineContext() // false
Choose what we want the context of 'this' to be using call, apply or bind
NAME OF METHOD | PARAMETERS | INVOKE IMMEDIATELY? |
---|---|---|
Call | thisArg, a, b, c, d , ... | Yes |
Apply | thisArg, [a,b,c,d, ...] | Yes |
Bind | thisArg, a, b, c, d , ... | No |
var person = {
firstName: "Colt",
sayHi: function(){
return "Hi " + this.firstName
},
determineContext: function(){
return this === person
},
dog: {
sayHello: function(){
return "Hello " + this.firstName
},
determineContext: function(){
return this === person
}
}
}
person.sayHi() // "Hi Colt"
person.determineContext() // true
person.dog.sayHello.call(person) // "Hello Colt"
person.dog.determineContext.call(person) // true
// Using call worked! Notice that we do NOT invoke sayHello or determineContext
var colt = {
firstName: "Colt",
sayHi: function(){
return "Hi " + this.firstName
}
}
var elie = {
firstName: "Elie",
// Look at all this duplication :(
sayHi: function(){
return "Hi " + this.firstName
}
}
colt.sayHi() // Hi Colt
elie.sayHi() // Hi Elie (but we had to copy and paste the function from above...)
// How can we refactor the duplication using call?
// How can we "borrow" the sayHi function from colt
// and set the value of 'this' to be elie?
Let's examine a very common use case
var colt = {
firstName: "Colt",
sayHi: function(){
return "Hi " + this.firstName
}
}
var elie = {
firstName: "Elie"
}
colt.sayHi() // Hi Colt
colt.sayHi.call(elie) // Hi Elie
// much better!
Solution
var colt = {
firstName: "Colt",
sayHi: function(){
return "Hi " + this.firstName
},
addNumbers: function(a,b,c,d){
return this.firstName + " just calculated " + (a+b+c+d);
}
}
var elie = {
firstName: "Elie"
}
colt.sayHi() // Hi Colt
colt.sayHi.apply(elie) // Hi Elie
// well this seems the same....but what happens when we start adding arguments?
It's almost identical to call - except the parameters!
colt.addNumbers(1,2,3,4) // Colt just calculated 10
colt.addNumbers.call(elie,1,2,3,4) // Elie just calculated 10
colt.addNumbers.apply(elie,[1,2,3,4]) // Elie just calculated 10
// What differences do you see?
var colt = {
firstName: "Colt",
sayHi: function(){
return "Hi " + this.firstName
},
addNumbers: function(a,b,c,d){
return this.firstName + " just calculated " + (a+b+c+d);
}
}
var elie = {
firstName: "Elie"
}
The parameters work like call, but bind returns a function with the context of 'this' bound already!
var elieCalc = colt.addNumbers.bind(elie,1,2,3,4) // function(){}...
elieCalc() // Elie just calculated 10
// With bind - we do not need to know all the arguments up front!
var elieCalc = colt.addNumbers.bind(elie,1,2) // function(){}...
elieCalc(3,4) // Elie just calculated 10
var colt = {
firstName: "Colt",
sayHi: function(){
setTimeout(function(){
console.log("Hi " + this.firstName)
},1000)
}
}
Very commonly we lose the context of 'this', but in functions that we do not want to execute right away!
var colt = {
firstName: "Colt",
sayHi: function(){
setTimeout(function(){
console.log("Hi " + this.firstName)
}.bind(this),1000)
}
}
Use bind to set the correct context of 'this'
colt.sayHi() // Hi undefined (1000 milliseconds later)
colt.sayHi() // Hi Colt (1000 milliseconds later)
function Person(firstName, lastName){
this.firstName = firstName
this.lastName = lastName
}
We can set the context of the keyword 'this' using the 'new' keyword - it does quite a bit more as well which we will discuss further when we talk about OOP
var elie = new Person("Elie", "Schoppik");
elie.firstName // "Elie"
elie.lastName // "Schoppik"