Context refers to the object where code is running.
Context can be assigned using the this keyword.
We will cover three types of context:
Default Context
Implicit Context
Explicit Context
This is a placeholder for an object
The default context is when the value of this refers to the global object
var myCar = 'Cybertruck';
function displayMyCar(){
// reference the global object with `this`
alert(this.myCar);
};
Note: only variables declared with var and function declarations are stored directly on the global object.
Implicit context is when the value of this refers to the object the code is running in.
const newCar = {
make: 'Tesla',
model: 'Model X',
year: 2019,
showOff: function(){
alert(`I drive a ${this.make}`);
}
};
newCar.showOff();
'this' refers to newCar
Explicit context is when the value of 'this' is explicitly defined.
There are three methods that allow us to define the context for our code:
.bind( )
.call( )
.apply( )
The .call( ) method allows us to define context by passing an object to the method, adding additional arguments separated by a comma.
const people = {
sayName: function(car, year){
alert(`My name is ${this.firstName} ${this.lastName}
and I drive a ${car} made in ${year}`);
};
};
// two new person objects
const personOne = {
firstName: 'Matias',
lastName: 'Perez Ferrero'
};
const personTwo = {
firstName: 'Matt',
lastName: 'Bodily'
};
people.sayName.call(personeOne, 'tesla', 2020);
people.sayName.call(personTwo, 'maserati', 2020);
Context is personOne
Context is personTwo
.apply( ) is nearly identical to call, with the difference being how additional arguments are passed in. Apply requires those arguments to be in an array.
const people = {
sayName: function(car, year){
alert(`My name is ${this.firstName} ${this.lastName}
and I drive a ${car} made in ${year}`);
};
};
// two new person objects
const personOne = {
firstName: 'Tayte',
lastName: 'Stokes'
};
const personTwo = {
firstName: 'Matt',
lastName: 'Bodily'
};
people.sayName.apply(personeOne, ['tesla', 2020]);
people.sayName.apply(personTwo, ['geo', 1990]);
Context is personOne
Context is personTwo
.bind( ) is similar to call, with the difference being it returns a new function with the specified context.
const people = {
sayName: function(car, year){
alert(`My name is ${this.firstName} ${this.lastName}
and I drive a ${car} made in ${year}`);
};
};
// two new person objects
const personOne = {
firstName: 'Tayte',
lastName: 'Stokes'
};
const personTwo = {
firstName: 'Matt',
lastName: 'Bodily'
};
const tayteCar = people.sayName.bind(personeOne);
const mattCar = people.sayName.bind(personTwo);
variable to save new function
Arrow functions behave differently than function declarations in regards to context.
They rely entirely on their lexical scope or where they are written. The value of this is for their containing object will be preserved inside the function.
let contextObj = {
regularMethod: function(){
//The value of this will be the contextObj
},
arrowMethod: () => {
//The value of this will be the window.
//This is because that is the value of this for contextObj
}
}
Constructor functions can be seen as blueprints for creating JavaScript objects.
Creating a constructor function is similar to creating a function declaration.
The difference is constructor function names start with a capital letter.
function Car(){
}
Constructors use the this keyword to imply the context of each object that is created from the constructor.
function Car(){
this.make = 'Tesla';
this.model = 'Cybertruck';
}
To build a new object from our constructor, we use the new keyword.
const myCar = new Car();
To make constructor functions more dynamic, we use parameters:
function Car(make, model){
this.make = make;
this.model = model;
}
const hondaAccord = new Car('Honda', 'Accord')
const mustang = new Car('Ford', 'Mustang')
{make: 'Honda', model: 'Accord'}
{make: 'Ford', model: 'Mustang'}
Constructor functions can also have methods written into them.
function Car(make, model){
this.make = make;
this.model = model;
this.honk = function(){
alert('Beep Beep');
}
}
One problem with this approach is that the honk method above is written each time we create an object from the Car constructor. This is where prototype methods come in.
Prototype methods are methods that sit within the prototype object of a function. We can create add prototype methods using dot notation:
function Car(make, model){
this.make = make;
this.model = model;
}
Car.prototype.honk = function(){
alert(`Beep Beep, I am a ${this.make}`)
}
When creating a prototype method in this way, it is not written to every new object, but every object has access to it through something called prototypical inheritance.
Prototypical inheritance refers to how an object can inherit prototype methods from a parent object. This makes are code more reusable and efficient.
function Car(make, model){
this.make = make;
this.model = model;
}
Car.prototype.honk = function(){
alert(`Beep Beep, I am a ${this.make}`)
}
const hondaAccord = new Car('Honda', 'Accord');
geoMetro.honk();
'Beep Beep, I am a Honda Accord'