js шесть наследование


Существует шесть методов наследования: наследование конструктора, наследование цепочки прототипов, комбинированное наследование, наследование прототипа, паразитное наследование и паразитное комбинированное наследование.

Во-первых, наследование конструктора

Используйте функции для реализации наследования

    //父类构造函数
    function Father(){
    
    
        this.name = "Father";
        this.say = function(){
    
    
            console.log(this.name);
        }
    }

    //子类构造函数
    function Son(){
    
    
        Father.call(this);  // 重点
    }

Важно: используйте call, чтобы ввести конструктор родительского класса в функцию подкласса (родительский класс копируется в функцию подкласса)

тестовое задание:

    let son1 = new Son();
    son1.say(); // Father

son1 успешно унаследовал атрибут имени и метод родительского класса

Но это не наследование в традиционном смысле, потому что объекты, генерируемые каждым подклассом Son, вызывающим родительский класс, независимы друг от друга, то есть, если родительский класс хочет иметь общий атрибут, который является общим для всех экземпляров подкласса, он Это не может быть достигнуто.

преимущество:

  1. Может наследовать несколько конструкторов (возможен множественный вызов)
  2. Все основные атрибуты независимы и не будут затронуты другими экземплярами.

Недостатки:

  1. Невозможно наследовать свойства и методы конструктора родительского класса (.prototype)
  2. Каждый новый экземпляр копирует родительский конструктор, если родительский класс очень большой, он будет занимать память
  3. Повторное использование общедоступных методов (повторное использование функций) не реализовано, и каждый раз создается новая функция вместо совместного использования.

2. Наследование цепочки прототипов

Самый примитивный способ, через наследование свойств прототипа

    //父级 构造函数
    function Father() {
    
    
        this.arr = [1,2,3];
    }

    //父级 原型属性
    Father.prototype.name = "tingting"
    
    //子级 构造函数
    function Son() {
    
    
    }

    //子级 原型属性: 继承父级
    Son.prototype = new Father() // 重点
    
    //创建子级的实例对象
    let son = new Son();

    console.log(son.name); // tingting

Важно: прототип подкласса равен экземпляру родительского класса. Son.prototype = new Father()

Объясните, как экземпляр son находит атрибут name.
Если не удается найти определенный атрибут объекта, он просматривает свой прототип и прекращает поиск до конца цепочки прототипов.

  • Первый поиск в самом объекте-сыне, если он не найден
  • Найдите (Отец ()) в Son.prototype, если не найден
  • На верхнем уровне Son.prototype.__proto__(Father.prototype)
  • Пока вы не найдете требуемое свойство или метод или не достигнете вершины цепочки прототипов Object.prototype

Но все атрибуты и методы дочернего экземпляра находятся в одном экземпляре родительского класса, поэтому, как только дочерний экземпляр изменяет свой метод, все остальные дочерние экземпляры будут затронуты.
Посмотрите на следующий код

    function Father() {
    
    
        this.arr = [1,2,3];
    }
    
    function Son() {
    
    
    }

    Son.prototype = new Father() 
    
    let son1 = new Son();
    let son2 = new Son();
    son1.arr.push(4);

    console.log(son1.arr); // 1,2,3,4
    console.log(son2.arr);// 1,2,3,4

После того, как дочерний экземпляр son1 изменяет arr, arr экземпляра son2 также изменяется

преимущество:

  1. просто

Недостатки:

  1. Невозможно передать параметры конструктору родительского класса
  2. Все экземпляры будут иметь общие свойства родительского экземпляра (экземпляр будет изменен, затем все свойства изменятся)

В-третьих, наследование композиции (цепочка прототипов + конструктор)

Сочетание наследования цепочки прототипов и наследования заимствования конструктора, объединение преимуществ двух, обычно используемых

    function Father(color) {
    
    
        this.color = color;
        
    }
    Father.prototype.print = function() {
    
    
        console.log(this.color);
    }
    function Son(color) {
    
    
        Father.call(this, color); // 借用构造函数继承
    }
    Son.prototype = new Father(); // 原型链继承let son1 = new Son('red');
    son1.print(); // redlet son2 = new Son('blue');
    son2.print(); // blue

В подклассе Son объект Father.call используется для вызова конструктора родительского класса, а Son.prototype назначается экземпляру родительского класса
. После того, как Father.call используется для вызова конструктора родительского класса, все последующие new Son()экземпляры, созданные с помощью Копировать копию свойств и методов, определенных в конструкторе родительского класса;
затем назначьте экземпляр родительского класса прототипу прототипа подкласса, все экземпляры подкласса могут совместно использовать свойства и методы прототипа родительского класса;
поэтому определите родительский класс При записи поместите частный свойства и методы в конструкторе и поместите общие свойства и методы в прототип

преимущество:

  1. Может передавать параметры
  2. Общие функции можно использовать повторно
    Недостатки:
  3. Дважды вызывал конструктор родительского класса, занимая память

Четвертый, наследование прототипа

Суть прототипного наследования - это на самом деле неглубокая копия , использующая объект в качестве шаблона для копирования нового объекта.

    // 封装一个函数容器,用来承载继承的原型
    function object(obj){
    
    
        function F(){
    
    }
        F.prototype = obj;
        return new F();
    }

    let father = {
    
    
        name: "father",
        arr: [1,2,3]
    }

    let son1 = object(father);

В объектной функции определите конструктор, используйте obj как шаблон, позвольте объекту-прототипу конструктора указывать на obj, а затем вернуть экземпляр конструктора, вы можете получить доступ ко всем свойствам и методам объекта obj.

Object.creat ()

В es5 добавлена ​​новая функция Object.create () для непосредственной реализации наследования прототипов. Приведенный
выше код можно переписать как:


    let father = {
    
    
        name: "father",
        arr: [1,2,3]
    }

    let son1 = Object.create(obj);

Суть по-прежнему заключается в наследовании цепочки прототипов, которая также будет разделять свойства родительского класса.

Пять, паразитарное наследование

Паразитное наследование заключается в том, чтобы снова инкапсулировать прототипное наследование, затем расширить новые методы объекта и затем вернуть новый объект. Его
можно понимать как добавление некоторых функций или свойств на основе прототипного наследования.

    function object(obj){
    
    
        function F(){
    
    }
        F.prototype = obj;
        return new F();
    }
    // 上面是原型式继承
    function create(obj){
    
    
        let clone = object(obj) // 或 Object.create(obj)

        clone.say = function(){
    
    
            console.log('123');
        }

        return clone;
    }
    // 用create函数封装了一遍,又增添了say方法
    let father = {
    
    
        name: "father",
        arr: [1,2,3]
    }

    let son = create(father);

    son.say(); // 123

Clone добавляет новые методы к объекту и, наконец, возвращается к клонированию, тем самым наследуя объект, возвращаемый объектом

преимущество:

  1. Нет необходимости создавать нестандартные типы

Недостатки:

  1. Прототип не используется и не может быть использован повторно.

6. Паразитарное комбинированное наследование (обычно используется)

Последний метод наследования является наиболее совершенным решением. Это
принцип реализации грамматики класса es6. Основная цель - устранить недостатки, связанные с необходимостью каждый раз нового отца в комбинированном наследовании, что приводит к выполнению конструктора родительского класса .

    function Father(color) {
    
    
        this.color = color;
    }
    Father.prototype.print = function() {
    
    
        console.log(this.color);
    }
    function Son(color) {
    
    
        Father.call(this, color); 
    }

    Son.prototype = Object.create(Father.prototype); // 划重点let son1 = new Son('red');
    son1.print(); // redlet son2 = new Son('blue');
    son2.print(); // blue

Это отличается от комбинации наследования, и единственное, что оригинал Son.prototype = new Father();изменен наSon.prototype = Object.create(Father.prototype);

Object.createМетод, упомянутый в прототипе, заключается в создании нового объекта с входящим объектом в качестве прототипа; после того, как новый объект создан, он назначается Son.prototype, поэтому прототип Сына в конечном итоге указывает на объект-прототип родительского класса, который new Fatherявляется таким же Эффект и не будет создавать избыточные экземпляры для занятия памяти, но также может обеспечить множественное наследование;

рекомендация

отblog.csdn.net/S_aitama/article/details/108757445
рекомендация