These are my notes while doing the course JavaScript Algorithms and Data Structures on https://www.freecodecamp.org. I highly recommend it if you prefer to try things directly rather than watching videos.
Objects have properties and methods.
let dog = {
name: "Spot",
numLegs: 4,
sayLegs: function() {return `This dog has ${this.numLegs} legs.`;}
};
dog.sayLegs();
Object Constructor Function
//constructor function
function Dog(name, color) {
this.name = name;
this.color = color;
this.numLegs = 4;
}
let myDog = new Dog("Max", "Brown");
myDog instanceof Dog; // true
- Constructors are defined with a capitalized name to distinguish them from other functions that are not
constructors
. - Constructors use the keyword
this
to set properties of the object they will create. Inside the constructor, this
refers to the new object it will create. - Constructors define properties and behaviors instead of returning a value as other functions might.
Get Objects Own Properties
let ownProps = [];
for (let property in myDog) {
if (myDog.hasOwnProperty(property)) ownProps.push(property);
}
console.log(ownProps); // returns [ "name", "color", "numLegs" ]
Prototype Properties to Reduce Duplicate Code
If all instances of an object have the same value for a property, define a prototype to share this property among all instances.
function Dog(name) {
this.name = name; //own property
}
// To add a sinlgle protoype property
Dog.prototype.numLegs = 4; // prototype property
// To add a few at once
Dog.prototype = {
constructor: Dog;
numLegs: 4,
sayName: function() {
console.log("My name is " + this.name);
}
}
Note: There are two kinds of properties: own
properties and prototype
properties!
let myDog = new Dog("Max");
let ownProps = [];
let prototypeProps = [];
for (let property in myDog) {
if (myDog.hasOwnProperty(property)) {
ownProps.push(property);
} else {
prototypeProps.push(property);
};
}
console.log(ownProps); // returns [ "name" ]
console.log(prototypeProps); // returns ["numLegs"]
Note: The hasOwnProperty
method is defined in Object.prototype
, which can be accessed by Dog.prototype
, which can then be accessed by myDog
. This is an example of the prototype
chain.
Constructor Property
Note that the constructor
property is a reference to the constructor function that created the instance. The advantage of the constructor
property is that it’s possible to check for this property to find out what kind of object it is.
console.log(myDog.constructor === Dog); //prints true
It’s generally better to use the instanceof
method to check the type of an object.
Inherit Behaviors from a Supertype
function Animal() { }
Animal.prototype = {
constructor: Animal,
eat: function() {
console.log("nom nom nom");
}
};
function Dog() { }
// Set the prototype of Dog to be an instance of Aninmal
Dog.prototype = Object.create(Animal.prototype);
// Set the constructor to Dog, else it would be function Animal(){...}
Dog.prototype.constructor = Dog;
// A method only the Dog needs
Dog.prototype.bark = function() {
console.log("Woof!");
};
let myDog = new Dog();
myDog.eat();
myDog.bark();
// To override an inherited method, just use the same method name as the one to override
Dog.prototype.eat = function() {
console.log("yami yami yami");
};
myDog.eat(); // returns yami yami yami
This is how JavaScript looks for the method:
- myDog => Is eat() defined here? No.
- Dog => Is eat() defined here? => Yes. Execute it and stop searching.
- Animal => eat() is also defined, but JavaScript stopped searching before reaching this level.
- Object => JavaScript stopped searching before reaching this level.
Mixin to Add Common Behavior Between Unrelated Objects
Inheritance does not work well for unrelated objects like Bird
and Boat
. They can both glide, but a Bird
is not a type of Boat
and vice versa.
For unrelated objects, it’s better to use mixins. A mixin allows other objects to use a collection of functions.
let bird = {
name: "Ducky",
numLegs: 2
};
let boat = {
name: "Titanic",
type: "CruiseShip"
};
let glideMixin = function(obj) {
obj.glide = function() {
console.log("Able to glide!");
}
}
// Adds the method glide to both objects
glideMixin(bird);
glideMixin(boat);
bird.glide();
boat.glide();
Private Properties (Closure)
function Bird() {
let weight = 15; // private variable
this.getWeight = function() {
return weight;
};
}
let ducky = new Bird();
ducky.getWeight(); // returns 15
Immediately Invoked Function Expression (IIFE)
// function declaration and function call
function makeNest() {
console.log("A cozy nest is ready");
}
makeNest();
//IIFE
(function () {
console.log("A cozy nest is ready");
})();
Note that the function has no name and is not stored in a variable. The two parentheses () at the end of the function expression cause it to be immediately executed or invoked.
Use an IIFE to Create a Module
let myModule = (function () {
return {
isCuteMixin: function (obj) {
obj.isCute = function () {
return true;
};
},
singMixin: function (obj) {
obj.sing = function () {
console.log("Singing to an awesome tune");
};
}
}
})();
myModule.singMixin(myDog);
myDog.sing(); // return Singing to an awesome tune