“This is the third day of my participation in the First Challenge 2022. For details: First Challenge 2022”
How to create objects and how to implement inheritance are two other common interview questions. Here we list ten ways to create objects and seven ways to implement inheritance.
Ten ways to create objects
1. New Object mode
const xiaoming = new Object({
name: 'Ming'.age: 18
})
Copy the code
You can abbreviate it in the following way
2. Brace abbreviations
const xiaoming = {
name: 'Ming'.age: 18
}
Copy the code
These two ways of creating objects are equivalent, and the code is redundant when creating objects with the same structure.
3. Factory function mode
The factory function solves the problem of code redundancy caused by the above two approaches
function createPerson(name, age) {
return {
name,
age,
getName: function() {
console.log(this.name, this.age)
}
}
}
const xiaoming = createPerson('Ming'.18)
Copy the code
This method is still a new Object in nature and cannot accurately determine the type of an Object based on its prototype Object
4. Constructor mode
Constructors can repeatedly create multiple objects with the same property structure and different property values.
function Person(name, age) {
this.name = name
this.age = age
this.getInfo = function() {
console.log(this.name, this.age)
}
}
const xiaoming = new Person('Ming'.18)
Copy the code
If the constructor contains methods, they are created repeatedly, resulting in a waste of memory
Fifth, the prototype object method
Putting common methods into prototypes avoids recreating methods with the same functionality and reduces memory usage. 👉 Click here to see how it works
function Person() {}
Person.prototype.name = "This man is lazy and has no name."
Person.prototype.age = 1
Person.prototype.getInfo = function() {
console.log(this.name, this.age)
}
const xiaoming = new Person()
// The attributes on the prototype are used here
xiaoming.getInfo() // "This person is lazy and has no name ", 1
// Add its own attributes
xiaoming.name = 'Ming'
xiaoming.age = 18
// Use its own attributes
xiaoming.getInfo() // "xiao Ming ", 18
Copy the code
This approach also leads to code redundancy
6. Hybrid mode
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.getInfo = function() {
console.log(this.name, this.age)
}
const xiaoming = new Person(name, age)
Copy the code
Although this approach solves the problem of code redundancy, it does not conform to the idea of object-oriented encapsulation.
7. Dynamic mixing
function Person(name, age) {
this.name = name
this.age = age
if (Person.prototype.getInfo === "undefined") {
Person.prototype.getInfo = function() {
console.log(this.name, this.age)
}
}
}
// The getInfo method is added to Person.prototype the first time it is called
const xiaoming = new Person("Xiao Ming".18)
const xiaoguang = new Person("Little light".15)
Copy the code
The downside of this approach is that it is semantically inconsistent, and only the first object is created when the if judgment is used
Parasitic constructors
By calling other constructors in a function, this approach is also a form of inheritance.
function Person(name, age) {
this.name = name
this.age = age
if (Person.prototype.getInfo === "undefined") {
Person.prototype.getInfo = function() {
console.log(this.name, this.age)
}
}
}
function Programmer(name, age, lang) {
const p = new Person(name, age)
p.lang = lang
return p
}
const xiaoming = Programmer("Xiao Ming".18."JavaScript")
const xiaoguang = Programmer("Little light".15."C++")
Copy the code
Nine, class
Class is a new syntax for creating objects in ES6, which is essentially a constructor, just a syntactic sugar. This syntax takes care of all the cases we’ve mentioned above.
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
getInfo() {
console.log(this.name, this.age)
}
}
const xiaoming = new Person("Xiao Ming".18)
Copy the code
Ten, closures
It is also possible to create objects using the features of closures. This approach has the advantage of not using this and new. The disadvantage is easy to cause memory leaks.
function Person(name, age) {
return {
getName() {
return name
},
setName: function(value) {
name = value
},
getAge: function() {
return age
}
}
}
const xiaoming = Person("Xiao Ming".18)
const xiaoguang = Person("Little light".15)
console.log(xiaoming.getName()) / / xiao Ming
console.log(xiaoguang.getName()) / / light
xiaoming.setName("Little Ming disguised as a little light.")
console.log(xiaoming.getName()) // Xiao Ming disguised as a light
Copy the code
There are seven ways to implement inheritance
First, prototype chain inheritance
The disadvantage of using an instance of a parent class as a prototype for a subclass is that you cannot pass arguments to the parent constructor when creating an instance of a subclass
function Animal(name) {
this.name = name
this.age = age
this.say = function() {
console.log(this.name)
}
}
Animal.prototype.eat = function(food) {
console.log(`The ${this.name}Is eating:${food}`)}function Cat() {}
Cat.prototype = new Animal() // Set prototype directly to Animal instance object
Cat.prototype.name = 'cat'
const cat = new Cat()
cat.eat("Cat food")
Copy the code
Constructor inheritance
Advantages:
- The problem of modifying reference attribute of parent class in prototype chain inheritance is solved
- You can now pass arguments to the superclass constructor
Disadvantages:
- An instance is not an instance of a parent class, only an instance of a subclass!
- Function reuse is not possible; each subclass has a copy of the parent class instance function
function Animal(name) {
this.name = name
this.say = function(sound) {
console.log(`The ${this.name}Said:${sound}`)
}
}
Animal.prototype.eat = function(food) {
console.log(`The ${this.name}eat${food}`)}function Cat(name, age) {
Animal.call(this, name) // Build with Cat
this.age = age
}
const cat = new Cat('the cat'.1)
cat.say('meow ~') / / OK!
cat.eat('Dried fish') // Throw wrong!! Because cat is not an instance of a parent class, it is only an instance of a subclass, and it cannot call eat
Copy the code
Instance inheritance
The disadvantage is also obvious. The result of a “subclass instance” is actually an instance of the parent class, and the “subclass instance” cannot call its own prototype method
function Animal(name) {
this.name = name
this.say = function(sound) {
console.log(`The ${this.name}Said:${sound}`)
}
}
Animal.prototype.eat = function(food) {
console.log(`The ${this.name}eat${food}`)}function Cat(name, age) {
const p = new Animal(name) // Create a subtype instance
p.age = age
return p // Note that this is an instance of the parent class, so it doesn't matter if we call Cat with or without new
}
Cat.prototype.jump = function() {
console.log('jump! ')}// Call new directly
const cat = new Cat('the cat'.1)
cat.eat('Dried fish') // The cat eats dried fish
cat.jump() / / wrong
Copy the code
Copy inheritance
Use for in to access Prototype features for copy inheritance. Disadvantages of this approach:
- Cannot get the parent class
for in
Traversal method. - Every time
new
Each child instance recreates the parent instance and copies a copy of the parent attributes
function Animal(name) {
this.name = name
this.say = function(sound) {
console.log(`The ${this.name}Said:${sound}`)
}
}
Animal.prototype.eat = function(food) {
console.log(`The ${this.name}eat${food}`)}function Cat(name, age) {
const animal = new Animal(name) // The disadvantage is that every time Cat is called, the new Animal and the copy operation will be performed
for (let p in animal) { // Use for in to access prototype features
Cat.prototype[p] = animal[p] // Some non-enumerable attributes cannot be accessed
}
this.age = age
}
const cat = new Cat('the cat'.1)
cat.eat('Dried fish') // The cat eats dried fish
Copy the code
5. Combinatorial inheritance
function Animal(name) {
this.name = name
this.say = function(sound) {
console.log(`The ${this.name}Said:${sound}`)
}
}
Animal.prototype.eat = function(food) {
console.log(`The ${this.name}eat${food}`)}function Cat(name, age) {
Animal.call(this, name) // Constructor inheritance
this.age = age
}
Cat.prototype = new Animal() // Prototype chain inheritance
Cat.prototype.constructor = Cat // Point the constructor of the prototype to itself
const cat = new Cat('the cat'.1)
Copy the code
Parasitic combination inheritance
Inheriting internal properties and methods through constructor inheritance inherits internal properties and methods by creating an empty class to inherit a parent class prototype, and then assigning an instance to a subclass’s prototype
function Animal(name) {
this.name = name
this.say = function(sound) {
console.log(`The ${this.name}Said:${sound}`)
}
}
Animal.prototype.eat = function(food) {
console.log(`The ${this.name}eat${food}`)}function Cat(name, age) {
Animal.call(this, name) // Constructor inheritance
this.age = age
}
// Implement inheritance on the prototype by creating an empty class to inherit the parent's prototype and then assigning an instance to the child's prototype
(function() {
const Super = function() {} // Create an empty class
Super.prototype = Animal.prototype
Cat.prototype = new Super() // Use the instance as the prototype of the subclass}) ()const cat = new Cat('the cat'.1)
cat.eat('Dried fish')
Copy the code
ES6 extends extends
class Animal {
constructor(name) {
this.name = name
}
eat(food) {
console.log(`The ${this.name}eat${food}`)}}class Cat extends Animal {
constructor(name, age) {
super(name)
this.age = age
}
}
const cat = new Cat('the cat'.1)
Copy the code