Несколько способов реализовать наследование в js

внешний интерфейс JavaScript модульный тест

Я часто просматриваю различные статьи, изучаю различные техники, читаю, не использую, забываю.

Хорошая память не так хороша, как плохое письмо!

Концепция наследования:

Пример механизма наследования

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

В этом примере shape является базовым классом для эллипсов и многоугольников (от которого наследуются все классы). Circle наследует Ellipse, поэтому Circle является подклассом Ellipse, а Ellipse является надклассом Circle. Точно так же треугольники, прямоугольники и пятиугольники являются подклассами Polygon, который является их суперклассом. Наконец, Square наследуется от Rectangle.

Следующая диаграмма представляет собой диаграмму, объясняющую отношения между Shape и его подклассами:

继承机制 UML 图示实例


Прежде чем объяснять наследование, давайте разберемся с процессом создания объекта в JavaScript.

function Person(name){
    //调用new的过程相当于 var this=new Object();
    //给this对象赋值
    //最后return this;
    this.name=name;
};
Person.prototype.getName=function(){
return this.name;
};
var a=new Person("seven");
console.log(a.name); //输出:seven
console.log(a.getName); //输出:seven

console.log(Object.getPrototypeOf(a)===Person.prototype); //输出:true

Функции JavaScript можно вызывать как обычные функции или как конструкторы.


Наследование прототипов в javaScript

Правила прототипирования:

  • 1. Все данные являются объектами
  • 2. Получить объект — это не инстанцировать класс, а найти объект как прототип и клонировать его.
  • 3. Объект запомнит свой прототип (__proto__)
  • 4. Если объект не может ответить на запрос, ta делегирует запрос прототипу автоматического конструктора


способ наследования

Ecmascript реализует наследство более чем в одном из способов. Это связано с тем, что механизм наследования в JavaScript не указан явно, но реализован через имитацию. Это означает, что все детали наследования не полностью обрабатываются переводчиком. Как разработчик, вы имеете право решать, какой метод наследования работает лучше всего.

олицетворение объекта

Поскольку конструктор — это просто функция, вы можете сделать конструктор ClassA методом ClassB, а затем вызвать его. ClassB получит свойства и методы, определенные в конструкторе ClassA. Например, определите ClassA и ClassB следующим образом:

function ClassA(sColor) {
    this.color = sColor;
    this.sayColor = function () {
        alert(this.color);
    };
}
function ClassB(sColor) {
    this.newMethod = ClassA;
    this.newMethod(sColor);
    delete this.newMethod;
}

В этом коде ClassA получает метод newMethod (помните, имя функции — это просто указатель на него). Затем вызывается метод, которому передается параметр sColor конструктора ClassB. Последняя строка кода удаляет ссылку на ClassA, чтобы его нельзя было вызвать позже.

Все новые свойства и новые методы должны быть определены после удаления строки кода для нового метода. В противном случае соответствующие свойства и методы суперкласса могут быть переопределены:

function ClassB(sColor, sName) {
    this.newMethod = ClassA;
    this.newMethod(sColor);
    delete this.newMethod;

    this.name = sName;
    this.sayName = function () {
        alert(this.name);
    };
}

Чтобы продемонстрировать, что предыдущий код работает, запустите следующий пример:

var objA = new ClassA("blue");
var objB = new ClassB("red", "John");
objA.sayColor();	//输出 "blue"
objB.sayColor();	//输出 "red"
objB.sayName();		//输出 "John"

Вы можете использовать метод Call для его оптимизации.

function ClassB(sColor, sName) {
    //this.newMethod = ClassA;
    //this.newMethod(color);
    //delete this.newMethod;

    ClassA.call(this, sColor);
    this.name = sName;
    this.sayName = function () {
        alert(this.name);
    };
}

Этот способ простоClassB вызывает ClassA и присваивает это значение ClassB

цепочка прототипов

function ClassA() {
}

ClassA.prototype.color = "blue";
ClassA.prototype.sayColor = function () {
    alert(this.color);
};

function ClassB() {
}

ClassB.prototype = new ClassA();

Магия прототипа заключается в последней строке кода. Здесь установите свойство прототипа ClassB на экземпляр ClassA. Потому что вам нужны все свойства и методы ClassA, но вы не хотите размещать их один за другим в свойстве прототипа ClassB. Есть ли лучший способ, чем присвоить экземпляр ClassA свойству прототипа?

Вызывается конструктор ClassA без передачи аргументов. Это стандартная практика в цепочках прототипов. Убедитесь, что конструктор не имеет параметров.

Подобно олицетворению объекта, все свойства и методы подкласса должны появиться после назначения свойства прототипа, потому что все методы, назначенные до него, удаляются. Почему? Поскольку свойство прототипа заменяется новым объектом, исходный объект с добавленным новым методом будет уничтожен. Итак, код для добавления атрибута name и метода sayName() в класс ClassB выглядит следующим образом:

function ClassB() {
}

ClassB.prototype = new ClassA();

ClassB.prototype.name = "";
ClassB.prototype.sayName = function () {
    alert(this.name);
};

Вы можете протестировать этот код, запустив следующий пример:

var objA = new ClassA();
var objB = new ClassB();
objA.color = "blue";
objB.color = "red";
objB.name = "John";
objA.sayColor();
objB.sayColor();
objB.sayName()

Смешивание

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

function ClassA(sColor) {
    this.color = sColor;
}

ClassA.prototype.sayColor = function () {
    alert(this.color);
};

function ClassB(sColor, sName) {
    ClassA.call(this, sColor);//对象冒充
    this.name = sName;
}

ClassB.prototype = new ClassA();//原型

ClassB.prototype.sayName = function () {
    alert(this.name);
};

В конструкторе ClassB притворитесь, что наследуете свойство sColor класса ClassA с объектом. Наследовать методы класса ClassA, используя цепочку прототипов.

ES6 реализует класс, который можно наследовать с помощью ключевого слова extends.

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y);    this.color = color; // 正确
  }
}

Преобразовать в es5

"use strict";

function _possibleConstructorReturn(self, call) { 
  return call && (typeof call === "object" || typeof call === "function") ? call : self; 
}

function _inherits(subClass, superClass) { 
  subClass.prototype = Object.create(
      superClass && superClass.prototype, 
      { 
      constructor: { 
        value: subClass, 
        enumerable: false, 
        writable: true, 
        configurable: true 
      } 
      }
  );
    if (superClass) {
      Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
    }
  }

var Point = function Point(x, y) {
  this.x = x;
  this.y = y;
};

var ColorPoint = function (_Point) {
  _inherits(ColorPoint, _Point);

  function ColorPoint(x, y, color) {
    var _this = _possibleConstructorReturn(this, (ColorPoint.__proto__ || Object.getPrototypeOf(ColorPoint)).call(this, x, y));

    _this.color = color; // 正确
    return _this;
  }

  return ColorPoint;l
}(Point);

Здесь мы сосредоточимся на наследовании в ES5.

1. _inherits, первое использованиеObject.create будет родительским классомПрототип точки скопирован в подклассКолорПойнт

2. Смонтируйте конструктор родительского класса в дочерний класс__прото__ на

, сохранить приложение в родительском классе

3. При вызове подкласса
ColorPoint, вызываемый во время инициализацииColorPoint.__proto__.call(this, x, y), смонтировать свойства в родительском классе к этому в подклассе

Наследование неконструкторов

Например, сейчас есть объект под названием «Китайский».

var Chinese = {
    nation:'中国'
  };

Также есть объект под названием «доктор».


 var Doctor ={
    career:'医生'
  }

Как сделать, чтобы "Доктор" наследовал "китайский", то есть как сгенерировать объект "Китайский доктор"?

Вы можете воспользоваться пустым конструктором:

function extends(o) {
    function F() {}
    F.prototype = o;
    return new F();
  }
var Doctor = object(Chinese);
Doctor.career = '医生';

Вы также можете использовать Object.create()

var Doctor = Object.create(Chinese);
Doctor.career = '医生';

Это заканчивается здесь!