Обновление: Спасибо за вашу поддержку.Недавно официальный сайт блога был выкинут, чтобы каждый мог его систематически читать.В будущем будет больше контента и больше оптимизации.Нажмите здесь, чтобы просмотреть
Обновление: на основе семи распространенных схем наследования было добавлено наследование классов ES6, так что теперь их восемь.
------ Далее идет текст ------
1. Наследование цепочки прототипов
Связь между конструкторами, прототипами и экземплярами: у каждого конструктора есть объект-прототип, объект-прототип содержит указатель на конструктор, а экземпляр содержит указатель на объект-прототип.
Суть наследования в том.скопировать, т.е. переписать объект-прототип и заменить его экземпляром нового типа.
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
}
function SubType() {
this.subproperty = false;
}
// 这里是关键,创建SuperType的实例,并将该实例赋值给SubType.prototype
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
return this.subproperty;
}
var instance = new SubType();
console.log(instance.getSuperValue()); // true
Недостаток схемы цепочки прототипов: работа нескольких экземпляров над ссылочным типом будет нарушена.
function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){}
SubType.prototype = new SuperType();
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green,black"
2. Заимствование наследования конструктора
Используйте конструктор родительского класса для улучшения дочернего классаПример, что эквивалентно копированию экземпляра родительского класса в дочерний класс (без использования прототипа)
function SuperType(){
this.color=["red","green","blue"];
}
function SubType(){
//继承自SuperType
SuperType.call(this);
}
var instance1 = new SubType();
instance1.color.push("black");
alert(instance1.color);//"red,green,blue,black"
var instance2 = new SubType();
alert(instance2.color);//"red,green,blue"
Основной кодSuperType.call(this), вызываемый при создании экземпляра подклассаSuperTypeконструктор, такSubTypeКаждый экземпляр будет создавать копию свойств в SuperType.
недостаток:
- Может наследовать только от родительского классаПримерСвойства и методы, не могут наследовать свойства/методы прототипа
- Невозможно добиться повторного использования, каждый подкласс имеет копию функции экземпляра родительского класса, что влияет на производительность.
3, наследование композиции
Сочетание двух вышеуказанных методов называется наследованием композиции. Используйте цепочку прототипов для реализации парыпрототипНаследование свойств и методов, реализованное с использованием техники заимствованного конструктораПримерНаследование свойств.
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
// 继承属性
// 第二次调用SuperType()
SuperType.call(this, name);
this.age = age;
}
// 继承方法
// 构建原型链
// 第一次调用SuperType()
SubType.prototype = new SuperType();
// 重写SubType.prototype的constructor属性,指向自己的构造函数SubType
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29
var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27
недостаток:
- первый звонок
SuperType():даватьSubType.prototypeНапишите имя двух атрибутов, цвет. - второй звонок
SuperType():даватьinstance1Напишите имя двух атрибутов, цвет.
экземпляр объектаinstance1Два вышеприведенных свойства маскируют два одноименных свойства объекта-прототипа SubType.prototype. Поэтому недостатком шаблона композиции является то, что при использовании подкласса для создания экземпляра объекта в его прототипе будет два одинаковых свойства/метода.
4. Наследование прототипов
Используя пустой объект в качестве посредника, назначьте объект непосредственно прототипу конструктора пустого объекта.
function object(obj){
function F(){}
F.prototype = obj;
return new F();
}
object() выполняется один раз для объекта, переданного в浅复制, указывающий прототип конструктора F непосредственно на переданный объект.
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
недостаток:
- Цепочка прототипов наследует атрибуты ссылочного типа нескольких экземпляров, указывающих на одно и то же, и существует возможность подделки.
- Невозможно передать параметры
Также существует ES5Object.create()метод, который может заменить указанный выше объектный метод.
5. Паразитическое наследование
Ядро: на основе прототипного наследования улучшать объекты и возвращать конструкторы.
function createAnother(original){
var clone = object(original); // 通过调用 object() 函数创建一个新对象
clone.sayHi = function(){ // 以某种方式来增强对象
alert("hi");
};
return clone; // 返回这个对象
}
Основная функция функции — добавить в конструктор свойства и методы, чтобыФункция улучшения
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"
Недостатки (те же, что и у прототипного наследования):
- Цепочка прототипов наследует атрибуты ссылочного типа нескольких экземпляров, указывающих на одно и то же, и существует возможность подделки.
- Невозможно передать параметры
6. Наследование паразитарного состава
Наследование в сочетании с передачей параметров путем заимствования конструктора и паразитного шаблона
function inheritPrototype(subType, superType){
var prototype = Object.create(superType.prototype); // 创建对象,创建父类原型的一个副本
prototype.constructor = subType; // 增强对象,弥补因重写原型而失去的默认的constructor 属性
subType.prototype = prototype; // 指定对象,将新创建的对象赋值给子类的原型
}
// 父类初始化实例属性和原型属性
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
// 借用构造函数传递增强子类实例属性(支持传参和避免篡改)
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
// 将父类原型指向子类
inheritPrototype(SubType, SuperType);
// 新增子类原型属性
SubType.prototype.sayAge = function(){
alert(this.age);
}
var instance1 = new SubType("xyc", 23);
var instance2 = new SubType("lxy", 23);
instance1.colors.push("2"); // ["red", "blue", "green", "2"]
instance1.colors.push("3"); // ["red", "blue", "green", "3"]
Эффективность этого примера в том, что он вызывается только один разSuperTypeконструктор, и таким образом избегаетSubType.prototypeсоздавать ненужные, избыточные свойства в файлах . При этом цепочка-прототип остается неизменной, поэтому ее еще можно нормально использоватьinstanceof иisPrototypeOf()
Это самый зрелый метод, и он реализован библиотекой сейчас.
7. Наследование нескольких объектов путем смешивания
function MyClass() {
SuperClass.call(this);
OtherSuperClass.call(this);
}
// 继承一个类
MyClass.prototype = Object.create(SuperClass.prototype);
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// 重新指定constructor
MyClass.prototype.constructor = MyClass;
MyClass.prototype.myMethod = function() {
// do something
};
Object.assignположитOtherSuperClassФункция прототипа копируется вMyClassПрототипируйте, сделайте методы OtherSuperClass доступными для всех экземпляров MyClass.
8. Расширение наследования классов ES6
extendsКлючевые слова в основном используются в объявлениях классов или выражениях классов для создания класса, являющегося подклассом другого класса. вconstructorУказывает конструктор, в классе может быть только один конструктор, и будет сообщено о несколькихSyntaxErrorошибка, если явно не указан конструктор, будет добавлено значение по умолчаниюconstructorметод, пример использования следующий.
class Rectangle {
// constructor
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea()
}
// Method
calcArea() {
return this.height * this.width;
}
}
const rectangle = new Rectangle(10, 20);
console.log(rectangle.area);
// 输出 200
-----------------------------------------------------------------
// 继承
class Square extends Rectangle {
constructor(length) {
super(length, length);
// 如果子类中存在构造函数,则需要在使用“this”之前首先调用 super()。
this.name = 'Square';
}
get area() {
return this.height * this.width;
}
}
const square = new Square(10);
console.log(square.area);
// 输出 100
extendsОсновной код наследования выглядит следующим образом, и его реализация такая же, как и у вышеупомянутого паразитного комбинированного наследования.
function _inherits(subType, superType) {
// 创建对象,创建父类原型的一个副本
// 增强对象,弥补因重写原型而失去的默认的constructor 属性
// 指定对象,将新创建的对象赋值给子类的原型
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;
}
}
Суммировать
1. Разница между объявлением функции и объявлением класса
Объявления функций поднимаются, объявления классов — нет. Сначала вам нужно объявить свой класс, а затем получить к нему доступ, иначе код, подобный приведенному ниже, выдаст ошибку ReferenceError.
let p = new Rectangle();
// ReferenceError
class Rectangle {}
2. Разница между наследованием ES5 и наследованием ES6
-
Наследование в ES5 заключается в том, чтобы сначала создать экземпляр объекта подкласса, а затем добавить к нему метод суперкласса (Parent.call(this)).
-
Наследование в ES6 отличается: по сути, сначала создается объект экземпляра this родительского класса, а затем для его изменения используется конструктор подкласса. Поскольку у подкласса нет собственного объекта this, сначала должен быть вызван метод super() суперкласса, иначе новый экземпляр сообщит об ошибке.
Примечания к «Продвинутому программированию на JavaScript»: наследование
Object.create() из MDN
Класс MDN
общаться
Моя ссылка на Github выглядит следующим образом, добро пожаловать в Star
GitHub.com/100 миллионов акционеров/Нет...
Меня зовут Му Иян, я старший фронтенд-инженер в Netease. Каждую неделю я следую за мной, чтобы преодолеть трудности с фронтенд-интервью. Далее, позвольте мне познакомить вас с миром продвинутого интерфейса и подбодрить друг друга на пути к продвинутому!