Object-oriented programming is a programming paradigm that uses objects to represent real-world things. An object is a data structure that contains data and methods that can be used to manipulate that data. In OOP, objects are organized into classes, which define the properties and methods that objects of that class will have. JavaScript is a little different from other classic programming languages in that it is fully object-oriented, but it uses prototype-based programming rather than class-based programming.
To create objects, we can use constructor functions. A constructor function is a special type of function that is used to create objects. Here's an example:
function Ship() {
this.floats = true;
this.material = 'steel';
}
const myShip = new Ship();
console.log(myShip.floats); // Output: true
console.log(myShip.material); // Output: steelShip that has two properties, floats and material. We then instantiated a new object of the Ship class called myShip. We can access the properties of myShip using dot notation.floats property of the myShip object like this:console.log(floats); // Output: ReferenceError: floats is not definedTo access the properties of an object, we must use dot notation or bracket notation:
console.log(myShip.floats); // Output: true
console.log(myShip['material']); // Output: steelInheritance works a little differently than in other classic programming languages. JavaScript uses prototype-based programming, which means that each object has a private property called the prototype, which can have a prototype of its own. When we access a property or method on an object, JavaScript walks up the prototype chain to find it.
Here's an example:
const myObject = {
a: 1
};
const myOtherObject = Object.create(myObject);
myOtherObject.b = 2;
console.log(myOtherObject.a); // Output: 1
console.log(myOtherObject.b); // Output: 2myObject with a property a. We then created another object called myOtherObject using Object.create(), which takes myObject as its argument. We added a property b to myOtherObject. When we access the property a on myOtherObject, JavaScript walks up the prototype chain to find it on myObject.The prototype chain is a fundamental concept in JavaScript that provides a mechanism for inheritance.
Each object has a private property called theprototype, which can have a prototype of its own. Essentially, the prototype chain works by walking up the chain until it finds the method or property it's looking for, and it checks if it exists in the instance itself, then in the prototype of the instance, and so on until it reaches the end of the chain, which is the object prototype. This is how JavaScript does inheritance differently than some of the other traditional class-based object-oriented languages, where you define a class and then create an instance of that class.
Here's an example to illustrate the concept of the prototype chain:
const myObject = { a: 1 };
console.log(myObject.a); // 1
console.log(myObject.toString()); // [object Object]myObject, which has a property called a. We can access this property using dot notation. The second console.log statement demonstrates how the prototype chain works. The toString() method is called on myObject, but this method is not defined on the instance of the object. JavaScript then looks up the prototype chain to see if the method is defined on the prototype of the object. In this case, it is defined on the Object.prototype, so it returns the default toString() method.hasOwnProperty()hasOwnProperty is a method of the Object constructor that returns a boolean value indicating whether the object has the specified property as its own property (as opposed to inheriting it from the prototype chain).Here's an example to illustrate the hasOwnProperty() method:const myObject = { a: 1 };
console.log(myObject.hasOwnProperty('a')); // true
console.log(myObject.hasOwnProperty('toString')); // falsehasOwnProperty() method on myObject to check if it has the properties a and toString. The method returns true for a because it is an own property of the object. However, it returns false for toString because it is not an own property of the object, but rather it is inherited from the prototype chain.To create an object constructor, we use a function. Here's an example:
function Animal(name, age, breed) {
const obj = {};
obj.name = name;
obj.age = age;
obj.breed = breed;
return obj;
}name, age, and breed. We then create an object obj and set its properties to the values passed in as arguments. Finally, we return the object.new keyword in conjunction with our constructor function. Here's an example:const dogOne = new Animal('Spike', 3, 'Labrador');dogOne with properties name, age, and breed set to 'Spike', 3, and 'Labrador', respectively.prototype property. Here's an example:Animal.prototype.sayBreed = function() {
console.log(`My breed is ${this.breed}`);
};sayBreed to the Animal prototype, which we can then use on any object created by the Animal constructor.When creating Constructor Functions, it is often necessary to create more specialized objects that inherit from a more generic parent object. This is where Constructor Functions that invoke another Constructor Function come in. This pattern allows us to create a more specialized Constructor Function that inherits from a more generic parent Constructor Function.
To create a Constructor Function that invokes another Constructor Function, we use thecall() method. The call() method allows us to call a function that is defined elsewhere in the current context. In the context of a Constructor Function, this refers to the new object being created. We can pass this as the first argument to the call() method, which will allow the new object to inherit properties and methods from the parent object.Here's an example of creating a more specialized Constructor Function that invokes another Constructor Function:
function Animal(name, age) {
this.name = name;
this.age = age;
}
Animal.prototype.makeNoise = function() {
console.log('Generic animal noise');
}
function Dog(name, age, breed) {
Animal.call(this, name, age);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log('Bark bark woof');
}
const myDog = new Dog('Rufus', 3, 'Labrador');
myDog.makeNoise(); // Generic animal noise
myDog.bark(); // Bark bark woof
Animal, which takes in name and age as arguments and creates a new object with those properties. It also has a makeNoise method, which is inherited by any child Constructor Functions.We then have a more specialized Constructor Function Dog, which takes in name, age, and breed as arguments. We use the call() method to call the Animal Constructor Function, passing this as the first argument to inherit the name and age properties. We then set the breed property on the new object.We then use Object.create() to create a new object that inherits from Animal.prototype, which allows the new Dog object to inherit the makeNoise method. We set the constructor property of the Dog.prototype object to Dog so that it points to the Dog Constructor Function.Finally, we add a new bark method to the Dog.prototype object, which is a specialized method for Dog objects.When we create a new Dog object using the new keyword, we can see that it inherits the properties and methods from the parent Animal object, as well as the specialized bark method.function keyword, we use the class keyword to declare a class. class Person {
// class methods
}constructor method is a special method used for creating and initializing an object created with a class. It has to be called constructor and it can accept parameters. class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}We can declare a class using two ways:
We can use the class declaration to declare a class. It is a class statement that defines a new class with a given name using "class" keyword.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}We can also use a class expression to define a class. It is similar to function expression syntax.
const Person = class {
constructor(name, age) {
this.name = name;
this.age = age;
}
};greetings method to a Person class:class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greetings() {
console.log("Classes are cool.");
}
}extends keyword. The super keyword is used to call the parent's constructor and to call the parent's methods.
class Employee extends Person {
constructor(name, age, position) {
super(name, age);
this.position = position;
}
}Employee class extends the Person class and it has a position property. The super keyword is used to call the Person class's constructor, passing the name and age parameters to it.
Static methods are methods that belong to a class itself, rather than an instance of the class. This means that they are called on the class itself, rather than on an object created from the class.
static keyword. We then define the method as we would any other method.class Customer {
static sayHi() {
console.log('Hi with a smiley face');
}
}To call a static method, we use the class name, followed by the method name.
Customer.sayHi();Static methods are inherited just like any other property of a class. For example:
class Person {
static sayHey() {
console.log('Hey');
}
}
class Customer extends Person {}
Customer.sayHey(); // Output: 'Hey'Static methods are useful when we want to define a method that belongs to a class itself, rather than to an instance of the class. For example, we might use a static method when we want to perform some kind of comparison or logic on multiple instances of a class. We might also use a static method when we want to group together related functionality in a class.