предисловие
ПредыдущийЯ рассмотрел основы наследования — прототипы и цепочки прототипов. Я очень рад видеть, что кто-то что-то получает после прочтения моего технического обмена, я также смиренно принимаю чье-то мнение.
Прежде чем говорить о нескольких способах наследования, я намерен сначала рассказать о нем — «Кун Иджи».
Что меня больше всего впечатлило в статье «Конг Ицзи», так это действие Конг Джии, линия диалога и вопрос.
Одно действие: сбросить девять монет
Строка диалога: Кража книг не может считаться воровством… Можно ли считать воровством дело ученого?
Вопрос: Как написать хуэйский характер Хуэй Сяндоу
Такой ученый, как Кун Ицзи, глубоко отравленный имперским экзаменационным образованием, часто обращал внимание на некоторые бесполезные символы и считал их знаниями и навыками. Способность знать, как писать «хуэй»?
Я думал об этом. Кажется, интервьюер отвечает: я не знаю, есть ли несколько способов написать return, но я хочу знать, сколько способов можно написать наследование.
Итак, в седьмой день первого лунного месяца строительство благоприятно, и это интересный способ приветствовать новых учеников, узнавая о нескольких способах наследования.
Введите вопрос
существуетJavaScript
серединанаследоватьявляется очень важным понятием. Нам нужно понять, пожалуйста, дайте больше советов.
Цель: упростить логику и структуру кода и добиться повторного использования кода.
Далее, давайте изучим следующие 8 видовJavaScript
Реализовать метод наследования.
реализация наследства
Рекомендуемое наследование композиции (4), паразитарное наследование композиции (7), наследование ES6 (8)
1. Метод цепочки прототипов (с использованием прототипа)
Основная идея заключается в использовании прототипов, позволяющих одному ссылочному типу наследовать методы и экземпляры другого ссылочного типа.
код показывает, как показано ниже
function staff(){
this.company = 'ABC';
}
staff.prototype.companyName = function(){
return this.company;
}
function employee(name,profession){
this.employeeName = name;
this.profession = profession;
}
// 继承 staff
employee.prototype = new staff();
// 将这个对象的 constructor 手动改成 employee,否则还会是 staff
employee.prototype.constructor = employee;
// 不使用对象字面量方式创建原型方法,会重写原型链
employee.prototype.showInfo = function(){
return this.employeeName + "'s profession is " + this.profession;
}
let instance = new employee('Andy','front-end');
// 测试
console.log(instance.companyName()); // ABC
console.log(instance.showInfo()); // "Andy's profession is front-end"
// 通过 hasOwnProperty() 方法来确定自身属性与其原型属性
console.log(instance.hasOwnProperty('employeeName')) // true
console.log(instance.hasOwnProperty('company')) // false
// 通过 isPrototypeOf() 方法来确定原型和实例的关系
console.log(employee.prototype.isPrototypeOf(instance)); // true
console.log(staff.prototype.isPrototypeOf(instance)); // true
console.log(Object.prototype.isPrototypeOf(instance)); // true
существующие проблемы
Самые большие проблемы с наследованием реализации цепочки прототипов:
Когда значение ссылочного типа существует в прототипе, экземпляр может изменить его значение.
function staff(){
this.test = [1,2,3,4];
}
function employee(name,profession){
this.employeeName = name;
this.profession = profession;
}
employee.prototype = new staff();
let instanceOne = new employee();
let instanceTwo = new employee();
instanceOne.test.push(5);
console.log(instanceTwo.test); // [1, 2, 3, 4, 5]
Ввиду этой проблемы: поэтому мы будем использовать только цепочку прототипов, чтобы на практике меньше добиваться наследования.
резюме
- На основе конструкторов и цепочек прототипов
- пройти через
hasOwnProperty()
метод определения собственных свойств и свойств их прототипов - пройти через
isPrototypeOf()
метод для определения отношения между прототипом и экземпляром - Значение ссылочного типа в прототипе можно изменить в экземпляре
2. Наследовать только объект-прототип родительского конструктора
Отличие этого метода от первого заключается в том, что:
employee.prototype = new staff();
Измените его на:
Employee.prototype = Person.prototype;
преимущество
- Нет необходимости создавать новые экземпляры объектов при построении отношений наследования.
- Поскольку объект-прототип является общим, нет необходимости проходить цепочку прототипов при доступе к объекту, и эффективность, естественно, высока.
недостаток
- Как и в случае с методом 1, изменения дочернего объекта повлияют на родительский объект.
резюме
- Основан на конструкторе, цепочка прототипов не используется.
- Дочерний объект и родительский объект совместно используют объект-прототип
В-третьих, позаимствовать метод конструктора
Этот метод может решить проблему изменения значения ссылочного типа в прототипе.
function staff(){
this.test = [1,2,3];
}
staff.prototype.companyName = function(){
return this.company;
}
function employee(name,profession){
staff.call(this);
this.employeeName = name;
this.profession = profession;
}
// 不使用对象字面量方式创建原型方法,会重写原型链
employee.prototype.showInfo = function(){
return this.employeeName + "'s profession is " + this.profession;
}
let instanceOne = new employee('Andy','front-end');
let instanceTwo = new employee('Mick','after-end');
instanceOne.test.push(4);
// 测试
console.log(instanceTwo.test); // [1,2,3]
// console.log(instanceOne.companyName()); // 报错
// 通过 hasOwnProperty() 方法来确定自身属性与其原型属性
console.log(instanceOne.hasOwnProperty('test')) // true
// 通过 isPrototypeOf() 方法来确定原型和实例的关系
console.log(staff.prototype.isPrototypeOf(instanceOne)); // false
Из вышеприведенных результатов видно, что:
- Заимствование метода конструктора может решить проблему изменения значения ссылочного типа в прототипе.
- Но
instanceOne
а такжеstaff
Цепочки прототипов больше нет
недостаток
- Может наследовать только свойства и методы экземпляра родительского объекта, но не свойства и методы прототипа родительского объекта.
- Повторное использование функций невозможно, каждый дочерний объект имеет копию экземпляра родительского объекта, а производительность не оптимальна.
В-четвертых, наследование композиции (рекомендуется)
Он относится к классическому методу наследования, который сочетает в себе технологию цепочки прототипов и технологию заимствованного конструктора, каждая из которых использует свои сильные стороны.
function staff(){
this.company = "ABC";
this.test = [1,2,3];
}
staff.prototype.companyName = function(){
return this.company;
}
function employee(name,profession){
// 继承属性
staff.call(this);
this.employeeName = name;
this.profession = profession;
}
// 继承方法
employee.prototype = new staff();
employee.prototype.constructor = employee;
employee.prototype.showInfo = function(){
return this.employeeName + "'s profession is " + this.profession;
}
let instanceOne = new employee('Andy','front-end');
let instanceTwo = new employee('Mick','after-end');
instanceOne.test.push(4);
// 测试
console.log(instanceTwo.test); // [1,2,3]
console.log(instanceOne.companyName()); // ABC
// 通过 hasOwnProperty() 方法来确定自身属性与其原型属性
console.log(instanceOne.hasOwnProperty('test')) // true
// 通过 isPrototypeOf() 方法来确定原型和实例的关系
console.log(staff.prototype.isPrototypeOf(instanceOne)); // true
преимущество
- Методы, определенные в прототипах, можно использовать повторно.
- Это может гарантировать, что каждая функция имеет свои собственные свойства, что может решить проблему изменения значения ссылочного типа в прототипе.
недостаток
-
staff
будет вызываться 2 раза: 1-йemployee.prototype = new staff();
, второй раз позвонитьstaff.call(this)
.
5. Наследование прототипа — Object.create()
Используя временный конструктор (пустой объект) в качестве посредника, назначьте объект непосредственно прототипу конструктора.
function object(obj){
function F(){}
F.prototype = obj;
return new F();
}
По сутиobject()
выполняет поверхностную копию переданного объекта, копируя конструкторF
Прототип указывает непосредственно на переданный объект.
var employee = {
test: [1,2,3]
}
let instanceOne = object(employee);
let instanceTwo = object(employee);
// 测试
instanceOne.test.push(4);
console.log(instanceTwo.test); // [1, 2, 3, 4]
недостаток
- Значение ссылочного типа в прототипе будет изменено
- Невозможно передать параметры
Кроме того, существует ES5Object.create()
метод нормализует прототипное наследование и может заменитьobject
метод.
6. Паразитическое наследование
Основной точкой: на основе прототипового наследования объект усиливается функцией, которая инкапсулирует процесс наследования, и объект возвращается
function createAnother(original){
var clone = object(original); // 通过调用 object() 函数创建一个新对象
clone.sayHi = function(){ // 以某种方式来增强对象
alert("hi");
};
return clone; // 返回这个对象
}
createAnother
Основная функция функции — добавление свойств и методов в конструктор для улучшения функции.
Недостатки (те же, что и у прототипного наследования):
- Значение ссылочного типа в прототипе будет изменено
- Невозможно передать параметры
7. Наследование паразитарного состава (рекомендуется)
Этот метод решает в основномнаследование композицииПроблема с двойным вызовом конструктора суперкласса.
function inheritPrototype(sub, super){
var prototype = Object.create(super.prototype); // 创建对象,父原型的副本
prototype.constructor = sub; // 增强对象
sub.prototype = prototype; // 指定对象,赋给子的原型
}
function staff(){
this.company = "ABC";
this.test = [1,2,3];
}
staff.prototype.companyName = function(){
return this.company;
}
function employee(name,profession){
staff.call(this, name);
this.employeeName = name;
this.profession = profession;
}
// 将父类原型指向子类
inheritPrototype(employee,staff)
let instanceOne = new employee("Andy", "A");
let instanceTwo = new employee("Rose", "B");
instanceOne.test.push(4);
// 测试
console.log(instanceTwo.test); // [1,2,3]
console.log(instanceOne.companyName()); // ABC
// 通过 hasOwnProperty() 方法来确定自身属性与其原型属性
console.log(instanceOne.hasOwnProperty('test')) // true
// 通过 isPrototypeOf() 方法来确定原型和实例的关系
console.log(staff.prototype.isPrototypeOf(instanceOne)); // true
Разработчики обычно считают, что паразитное наследование композиции является наиболее идеальной парадигмой наследования для ссылочных типов.
Восемь, наследование классов (рекомендуется)
Класс может пройтиextends
Ключевые слова реализуют наследование, что намного понятнее и удобнее, чем реализация наследования в ES5 путем изменения цепочки прототипов.
class staff {
constructor(){
this.company = "ABC";
this.test = [1,2,3];
}
companyName(){
return this.company;
}
}
class employee extends staff {
constructor(name,profession){
super();
this.employeeName = name;
this.profession = profession;
}
}
// 将父类原型指向子类
let instanceOne = new employee("Andy", "A");
let instanceTwo = new employee("Rose", "B");
instanceOne.test.push(4);
// 测试
console.log(instanceTwo.test); // [1,2,3]
console.log(instanceOne.companyName()); // ABC
// 通过 Object.getPrototypeOf() 方法可以用来从子类上获取父类
console.log(Object.getPrototypeOf(employee) === staff)
// 通过 hasOwnProperty() 方法来确定自身属性与其原型属性
console.log(instanceOne.hasOwnProperty('test')) // true
// 通过 isPrototypeOf() 方法来确定原型和实例的关系
console.log(staff.prototype.isPrototypeOf(instanceOne)); // true
super
ключевое слово, которое здесь представляет конструктор родительского класса, который используется для создания нового родительского классаthis
объект.
- Подклассы должны быть в
constructor
вызов методаsuper
метод, иначе будет сообщено об ошибке при создании нового экземпляра. Это потому, что подклассы не имеют своих собственныхthis
объект, но наследует родительский классthis
объект, а затем обработать его.- только звони
super
После этого вы можете использоватьthis
Ключевые слова, иначе сообщит об ошибке. Это связано с тем, что построение экземпляров подкласса основано на обработке экземпляра родительского класса, толькоsuper
метод для возврата экземпляра родительского класса.
Хотя `super` представляет конструктор родительского класса `A`, он возвращает экземпляр подкласса `B`, то есть `this` внутри `super` ссылается на `B`, поэтому `super()` здесь эквивалентно A.prototype.constructor.call(это)
Разница между наследованием реализации ES5 и ES6
Наследование ES5, суть в том, чтобы сначала создать объекты-экземпляры подклассовthis
, а затем добавьте метод родительского класса вthis
над(Parent.apply(this)
).
Механизм наследования в ES6 совершенно другой, суть в том, чтобы сначала создать экземпляр объекта родительского класса.this
(поэтому его нужно назвать первымsuper()
метод), а затем используйте конструктор подкласса для измененияthis
.
extends наследует основной код (паразитное наследование композиции)
function _inherits(subType, superType) {
subType.prototype = Object.create(superType && superType.prototype, {
constructor: {
value: subType,
enumerable: false,
writable: true,
configurable: true
}
});
if (superType) {
Object.setPrototypeOf
? Object.setPrototypeOf(subType, superType)
: subType.__proto__ = superType;
}
}
Отсюда видно, что:
- подкласс
__proto__
Свойства, представляющие наследование конструкторов, всегда указывают на родительский класс. - Подкласс
prototype
атрибут__proto__
Атрибуты, представляющие наследование методов, всегда указывают на родительский классprototype
Атрибуты.
Другое: ES6 может настраивать подклассы нативных структур данных (таких как Array, String и т. д.), чего ES5 делать не может.
Вышеупомянутые восемь методов наследования являются относительно распространенными методами наследования, и если вы понимаете механизм этих методов, проблема цепочки прототипов и наследования в будущих интервью не будет проблемой.
Ссылаться на
- Продвинутое программирование на JavaScript
- Голодание 6. Жуань Ифэн.com/#docs/class…
постскриптум
Я писала об этом больше двух недель.Главная причина в том,что ребенок только что вошел в мою жизнь.Мне приходится без конца заботиться о ребенке,и тратить много сил и времени на смену подгузников,кормление грудью,переодевание . Эта статья также была написана, пока ребенок спал.Если содержание статьи покажется вам рудиментарным, пожалуйста, потерпите меня и выдвиньте ценные мнения, и я буду пересматривать ее, когда у меня будет время в будущем.
В начале нового года не забудьте изначальный замысел
Серия интерфейсных словарей
Серия «Front-end Dictionary» будет постоянно пополняться, и в каждом выпуске я буду рассказывать о точке знаний, которая появляется все чаще. Надеюсь, что в процессе прочтения в тексте будут неточности или ошибки, буду очень признательна, если что-то почерпну из этой серии, тоже буду очень рада.
Если вы считаете, что мои статьи написаны хорошо, то можете обратить внимание на мой паблик в WeChat, в котором заранее будут раскрыты спойлеры.
Вы также можете добавить мой WeChat wqhhsd, добро пожаловать в общение.
следующее уведомление
[Внешний словарь] Сетевая основа, которую должен понимать внешний интерфейс