Built-in constructors and inheritance

Let’s start with two pictures

Two unrelated classes

Think about the relationship between the People class and the Student class

The Student class has all the attributes and methods that the People class has, and extends some of the attributes and methods

Student is a kind of People. **is a kind of person

This is the inheritance relationship: Student inherits from People

inheritance

Inheritance describes the “is a kind of” relationship between two classes

For example, students are a kind of “people”, so there is an inheritance relationship between human beings and students

People is ** “superclass” (or “superclass”, “base class”); Student is a “subclass” **(or “derived class”)

Subclasses enrich the parent class, making the class description more specific and detailed

More examples of inheritance relationships

1. Inheritance through the prototype chain

The key to inheritance is that subclasses must have all the attributes and methods of their parent class, and they should also be able to define their own unique attributes and methods

Make the prototype of the subclass constructor point to an instance of the parent class

It is common practice to implement inheritance using JavaScript’s unique prototype chain feature

// Parent human
function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    // this.arr = [33, 44, 55];
}

People.prototype.sayHello = function () {
    console.log(I was `The ${this.name}This year,The ${this.age}La `);
};

People.prototype.sleep = function () {
    console.log(this.name + "Go to sleep ZZZZ.");
};

// Subclass student class
function Student(name, age, sex, scholl, studentNumber) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.scholl = scholl;
    this.studentNumber = studentNumber;
}
// The core statement implements inheritance
Student.prototype = new People();

Student.prototype.study = function(){
    console.log(this.name + "Learning");
}
Student.prototype.exam = function(){
    console.log(this.name + "Taking exams, Ollie!");
}

// Subclasses can override the parent sayHello method
Student.prototype.sayHello = function(){
    console.log( ` salute! How do you doThe ${this.name}.The ${this.sex}, I come fromThe ${this.scholl}, IThe ${this.age}The `);
}

/ / instantiate
let hanmeimei = new Student("Han Meimei" , 12."Female"."Central Primary School" , 12110);

hanmeimei.study();
hanmeimei.exam();
hanmeimei.sayHello();
hanmeimei.sleep();

let yunmu = new People("YunMu".18."Male");
yunmu.sayHello();
Copy the code

The result is as follows

The problem of inheritance through a chain of prototypes

  • Problem 1: If a parent class has a reference type value in an attribute, the attribute is shared by all instances of the child class.
  • Problem 2: Subclass constructors often need to repeat many superclass-defined attributes. That is, the constructor of the subclass is not written elegantly;

2. Borrow constructors

  • To address the problems of including reference type values in stereotypes and the inelegance of subclass constructors, developers often use a technique called “by virtue of constructors,” also known as “fake objects” or “classical inheritance.”
  • The idea of borrowing constructors is simple: call the superclass constructor inside the subclass constructor, but be careful to use the call() binding context

We will modify the above example slightly

// Parent human
function People(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.arr = [33.44.55];
}

// Subclass student class
function Student(name, age, sex, scholl, studentNumber) {
    // Subclasses use call to bind the parent constructor to this and pass the value
    People.call(this, name, age, sex);
    this.scholl = scholl;
    this.studentNumber = studentNumber;
}

const xiaoming = new Student("Xiao Ming"."Male".12."Central School".100666);
console.log(xiaoming);
xiaoming.arr.push(77); 
console.log(xiaoming.arr); // [33, 44, 55, 77]
console.log(xiaoming.hasOwnProperty("arr")); // true

const xiaohong = new Student("Little red"."Female".11."Central School".100667);
console.log(xiaohong.arr); / / [55] 33, 44,
console.log(xiaohong.hasOwnProperty("arr")); // true
Copy the code

3. Combinatorial inheritance

Is the combination of prototype chain inheritance and constructor inheritance, inherit two advantages, also do pseudo-classical inheritance

Inheriting the attributes of the parent class and preserving the advantages of passing arguments by calling the parent constructor,

Then the functions can be reused by using the parent class instance as the prototype of the subclass

Composite inheritance is the most common inheritance pattern in]avaScript

// Subclass student class
function Student(name, age, sex, scholl, studentNumber) {
    // Subclasses use call to bind the parent constructor to this and pass the value
    People.call(this, name, age, sex);
    this.scholl = scholl;
    this.studentNumber = studentNumber;
}
// The core statement implements inheritance
Student.prototype = new People();
Copy the code

Disadvantages of combinatorial inheritance

  • The biggest problem with combinatorial inheritance is that in any case, you call the superclass constructor twice, right
  • Once when the subclass prototype is created, and once inside the subclass constructor

4. Original type inheritance

IE9+ began to support the 0bject.create() method, which allows you to create a new object for your prototype based on a specified object

const obj2 = Object.create(obj1);
Copy the code

const obj1 = {
    a: 1.b: 2.c: 3.test() {
        console.log(this.a + this.b); }};const obj2 = Object.create(obj1, {
    // Add new attributes to obj2
    d: {
        value: 99
    }, 
    // Access overshadows the a attribute on the prototype
    a: {
        value: Awesome!}});console.log(obj2.__proto__ === obj1);       // true
console.log(obj2.a); / / 666
console.log(obj2.b); / / 2
console.log(obj2.c); / / 3
console.log(obj2.d); / / 99
obj2.test(); / / 668
Copy the code

If you want your new Object to be “similar” to an existing Object, use object.create () instead of creating a constructor

Object. Create () is compatible

  • How do YOU implement 0bject.create() in older browsers?
// The function creates a new object based on obj
function object(obj) { 
    // Create a temporary constructor
    function F() {}
    // Make the temporary constructor's prototype point to O, so that its new object, __proto__, points to O
    F.prototype = obj;
    // Return an instance of F
    return new F();
}
Copy the code

Parasitic inheritance

  • Write a function that takes an argument O, returns a new object p modeled after o, and adds a preset new method to p

const o1 = {
    name: "Xiao Ming".age: 12.sex: "Male"};const o2 = {
    name: "Little red".age: 11,d
    sex: "Female"};// Parasitic inheritance
function f(o) {
    // Create a new object based on o
    const p = Object.create(o);
    // Add two methods
    p.sayHello = function () {
        console.log("Hello, I am." + this.name + "This year" + this.age + "Old");
    };
    p.sleep = function () {
        console.log(this.name + "Sleeping");
    };

    return p;
}

// get p1 object from o1
const p1 = f(o1);
p1.sayHello(); // Hello, I am Xiao Ming and I am 12 years old

// Get p2 object from o2 object
const p2 = f(o2);
p2.sayHello(); // Hello, I am Xiao Hong and I am 11 years old
Copy the code
  • Parasitic inheritance is simply writing a function that enhances the object

  • Whenever you pass an object into this function, the function creates a new object from that object and assigns new preset methods to the new object

  • Parasitic inheritance is also a useful pattern in cases where objects are primarily considered rather than custom types and constructors

Disadvantages of parasitic inheritance

  • Using parasitic inheritance to add functions to objects is inefficient because functions cannot be reused, i.e. “methods are not written to Prototype.”
console.log(p1.sayHello == p2.sayHello); // false
Copy the code

Parasitic combinatorial inheritance

  • Parasitic combinatorial inheritance: inherits properties by borrowing constructors and inherits methods through a mashup of stereotype chains
  • The basic idea behind this is that instead of calling the constructor of a supertype to specify the stereotype of a subtype,
  • ** All we need is a copy of the supertype prototype.
  • Essentially, you use parasitic inheritance to inherit the stereotype of the supertype and then assign the result to the stereotype of the subtype.
function People(name) {
    this.name = name;
}

People.prototype.eat = function () {
    console.log(this.name + " is eating");
};

function Stundent(name, age) {
    People.call(this, name);
    this.age = age;
}
Stundent.prototype = Object.create(People.prototype);
// The prototype object has a constructor attribute, which by default points to the prototype object's constructor.
Stundent.prototype.contructor = Stundent;

Stundent.prototype.study = function () {
    console.log(this.name + " is studying");
};

/ / test
let xiaoming = new Stundent("xiaoming".16);
console.log(xiaoming.name); // xiaoming
xiaoming.eat(); // xiaoming is eating
xiaoming.study(); // xiaoming is studying
Copy the code

The illustration is as follows:

7.ES6 class inheritance

  • The class keyword was introduced in ES6, and classes can be inherited using the extends keyword
  • You can also define static methods of a class using the static keyword
  • This is much cleaner and more convenient than ES5’s inheritance by modifying the prototype chain
  • Note that the class keyword is just syntactic sugar for the stereotype, and JavaScript inheritance is still implemented based on the stereotype.
class Person {
    // Class constructor
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    // Define the method
    showName() {
        console.log("Call method of parent class");
        console.log(this.name, this.age); }}const p1 = new Person("kobe".39);
console.log(p1);

// Define a subclass
class Student extends Person {
    constructor(name, age, salary) {
        super(name, age); // Call the parent constructor with super
        this.salary = salary;
    }
    showName() {
        // Define methods in the subclass itself
        console.log("Calling a subclass's method");
        console.log(this.name, this.age, this.salary); }}const s1 = new Student("yunmu".18.1000000);
console.log(s1);
s1.showName(); // yunmu 18 1000000
Copy the code

The instance operator.

  • The instanceof operator is used to check whether an object is an instanceof a class, as in:

function People() {}
function Student() {}
Student.prototype = Object.create(People.prototype);
const xiaoming = new Student();

/ / instanceof test
console.log(xiaoming instanceof Student); // true
console.log(xiaoming instanceof People); // true
Copy the code

Again, Ming can find the Student and People prototype properties along the prototype chain, so instanceof is true

Built-in constructor

  • JavaScript has many built-in constructors, such as Array (Array), Function (Function), and object (object)
  • Built-in constructors are very useful. All methods of this type are defined on the prototype of its built-in constructor. We can extend the functionality of a type by adding new methods to this object

// The built-in constructor for arrays. Any Array literal can be treated as an instance of Array
console.log([1.2] instanceof Array); // true
console.log([] instanceof Array); // true

// Creates an empty array of length 5
const arr = new Array(5);
console.log(arr); //[ <5 empty items> ]
console.log(arr.length); / / 5

// The built-in constructor of a Function. Any Function literal can be treated as an instance of Function
function fun() {}
function add(a, b) {
    return a + b;
}
console.log(fun instanceof Function); // true
console.log(add instanceof Function); // true

const decrement = new Function("a"."b"."return a - b");
console.log(decrement(8.3)); / / 5

// The built-in constructor for the object
console.log({ a: 1 } instanceof Object); // true
console.log({} instanceof Object); // true
const o = new Object(a); o.a =2;
o.b = 6;
console.log(o); // { a: 2, b: 6 }
Copy the code

Extension methods

// Methods like push POP are actually methods on array constructor prototypes
console.log(Array.prototype.hasOwnProperty("push")); // true
console.log(Array.prototype.hasOwnProperty("pop")); // true
console.log(Array.prototype.hasOwnProperty("splice")); // true

// Extend the qiuHE method
Array.prototype.total = function () {
    / / accumulator
    let sum = 0;
    // This represents the array that calls the total() method
    for (let i = 0; i < this.length; i++) {
        sum += this[i];
    }
    // Return the result
    return sum;
};

const arr1 = [1.2.3.4.5];
const result1 = arr1.total();
console.log(result1); / / 15

const arr2 = [2.8];
const result2 = arr2.total();
console.log(result2); / / 10
Copy the code

“Wrapper classes” for base type values

  • Number, String, and Boolean are wrapper classes for the three primitive type values that can be called with new to generate the “object” version of the primitive type values
const o = new Number(3);
console.log(o);
console.log(typeof o); // object
console.log(5 + o); / / 8

const s = new String("abc");
console.log(s);
console.log(typeof s); // object
console.log(String.prototype.hasOwnProperty("slice")); // true
console.log(String.prototype.hasOwnProperty("substring")); // true
console.log(String.prototype.hasOwnProperty("substr")); // true

const b = new Boolean(true);
console.log(b);
console.log(typeof b); // object
Copy the code

Built-in constructor relationships

  • Prototype is the end of the prototype chain of everything. In JavaScript, functions and arrays are all objects. Taking arrays as an example, the full prototype chain looks like this:

Testing:

console.log([1.2].__proto__ === Array.prototype); // true
console.log([1.2].__proto__.__proto__ === Object.prototype); // true

console.log([] instanceof Object); // true
console.log([] instanceof Array); // true

console.log(Object.prototype.__proto__); // null null has no __proto__
Copy the code
  • Any Function can be regarded as a Function “new”, so let’s have an imagination:
  • Function “Object” is a new Function. The answer is yes
  • Function is also a Function that can be viewed as an instance of itself

Testing:

console.log(Object.__proto__ === Function.prototype); // true
console.log(Function.__proto__ === Function.prototype); // true
console.log(Object.__proto__.__proto__ === Object.prototype); // true

console.log(Function instanceof Object); // true
console.log(Object instanceof Function); // true
console.log(Function instanceof Function); // true
console.log(Object instanceof Object); // true
Copy the code

If you think this article is good, give it a thumbs up.