предисловие
Здравствуйте, яВакагава. Это пятая статья из серии «Вопросы интервьюера», призванной помочь читателям улучшить
JS
базовые знания, в том числеnew、call、apply、this、继承
связанная информация.
面试官问系列
Статья выглядит следующим образом: Заинтересованные читатели могут нажать, чтобы прочитать.
1.Интервьюер спросил: Могу ли я смоделировать новый оператор, реализующий JS?
2.Интервьюер спросил: Могу ли я смоделировать метод привязки, реализующий JS?
3.Интервьюер спросил: Могу ли я смоделировать вызов и применить методы JS?
4.Интервьюер спросил: этот пункт JS
5.Интервьюер спросил: наследование JS
использовалReact
читателей знают, что часто используютextends
наследоватьReact.Component
.
// 部分源码
function Component(props, context, updater) {
// ...
}
Component.prototype.setState = function(partialState, callback){
// ...
}
const React = {
Component,
// ...
}
// 使用
class index extends React.Component{
// ...
}
Нажмите здесь, чтобы просмотреть исходный код React github
Интервьюер может задать этот вопросJS
Вопросы, связанные с наследством, такие как:ES6
изclass
Как реализовать наследование с помощью ES5. Говорят, что многие люди ответили плохо.
Связь между конструкторами, объектами-прототипами и экземплярами
Прежде чем понять расширение наследования, давайте рассмотрим отношения между конструкторами, объектами-прототипами и экземплярами. Код говорит:
function F(){}
var f = new F();
// 构造器
F.prototype.constructor === F; // true
F.__proto__ === Function.prototype; // true
Function.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null; // true
// 实例
f.__proto__ === F.prototype; // true
F.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null; // true
Автор нарисовал картинку, показывающую:
ES6 extends
Что делает наследование
Давайте сначала посмотрим на этот раздел, содержащий статические методы.ES6
Унаследованный код:
// ES6
class Parent{
constructor(name){
this.name = name;
}
static sayHello(){
console.log('hello');
}
sayName(){
console.log('my name is ' + this.name);
return this.name;
}
}
class Child extends Parent{
constructor(name, age){
super(name);
this.age = age;
}
sayAge(){
console.log('my age is ' + this.age);
return this.age;
}
}
let parent = new Parent('Parent');
let child = new Child('Child', 18);
console.log('parent: ', parent); // parent: Parent {name: "Parent"}
Parent.sayHello(); // hello
parent.sayName(); // my name is Parent
console.log('child: ', child); // child: Child {name: "Child", age: 18}
Child.sayHello(); // hello
child.sayName(); // my name is Child
child.sayAge(); // my age is 18
В этом коде есть две цепочки прототипов, не верьте, чтобы увидеть конкретный код.
// 1、构造器原型链
Child.__proto__ === Parent; // true
Parent.__proto__ === Function.prototype; // true
Function.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null; // true
// 2、实例原型链
child.__proto__ === Child.prototype; // true
Child.prototype.__proto__ === Parent.prototype; // true
Parent.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null; // true
Картинка стоит тысячи слов, я также нарисовал картинку, чтобы представить ее, как показано на рисунке:
Сочетание кода и диаграмм может быть известно.ES6 extends
Наследование, в основном:
-
- Положите конструктор подкласса (
Child
)Прототип(__proto__
) указывает на конструктор родительского класса (Parent
),
- Положите конструктор подкласса (
-
- экземпляр подкласса
child
Объект-прототип (Child.prototype
) Прототип(__proto__
) указывает на родительский классparent
Объект-прототип (Parent.prototype
).
- экземпляр подкласса
Эти две точки также являются двумя линиями, отмеченными на рисунке разными цветами.
-
- конструктор подкласса
Child
Унаследовал конструктор родительского классаParent
свойства . использоватьsuper
называется (ES5
затем используйтеcall
илиapply
параметр вызова).
- конструктор подкласса
То есть две линии отмечены на рисунке разными цветами.
Прочтите главу «Продвинутое программирование на JavaScript — 3-е издание».6.3继承
читатели должны знать, что это2和3小点
, точноПаразитическая композиционная наследственность, в книге нет примеров第1小点
.1和2小点
относятся к настройкам__proto__
Связь. Вопрос в том, что можно установить__proto__
Что насчет ссылки.
new
,Object.create
а такжеObject.setPrototypeOf
можно установить__proto__
Объяснять,__proto__
Этот способ записи является собственной реализацией производителя браузера.
Давайте посмотрим на картинку и кодnew
,new
__proto__ исходящего экземпляра указывает на конструкторprototype
,Этоnew
Список задач.
Возьмите отрывок из предыдущей статьи.Интервьюер спросил: Могу ли я смоделировать новый оператор, реализующий JS?, заинтересованные читатели могут нажать для просмотра.
new
Что вы наделали:
- Создается новый объект.
- Этот объект будет выполнен
[[Prototype]]
(то есть,__proto__
)Связь.- Результирующий новый объект привязывается к вызову функции
this
.- пройти через
new
Каждый созданный объект в конечном итоге будет[[Prototype]]
ссылка на эту функциюprototype
на объекте.- Если функция не возвращает тип объекта
Object
(ВключатьFunctoin
,Array
,Date
,RegExg
,Error
),Такnew
Вызовы функций в выражениях автоматически возвращают этот новый объект.
Object.create
ES5提供的
Object.create(proto, [propertiesObject])
метод создает новый объект, используя существующий объект для предоставления __proto__ вновь созданного объекта.
Он принимает два параметра, но вторым необязательным параметром является дескриптор атрибута (обычно не используется, по умолчаниюundefined
). для не поддерживаемыхES5
браузер,MDN
предоставляется наployfill
строить планы.MDN Object.create()
// 简版:也正是应用了new会设置__proto__链接的原理。
if(typeof Object.create !== 'function'){
Object.create = function(proto){
function F() {}
F.prototype = proto;
return new F();
}
}
Object.setPrototypeOf
ES6提供的
Object.setPrototypeOf()
Способ установки заданного прототипа объекта (т. е. внутреннего[[Prototype]]
имущество) к другому объекту илиnull
.Object.setPrototypeOf(obj, prototype)
`ployfill`
// 仅适用于Chrome和FireFox,在IE中不工作:
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
obj.__proto__ = proto;
return obj;
}
nodejs
Исходный код должен использовать эту реализацию унаследованной полезной функции.nodejs utils inherits
function inherits(ctor, superCtor) {
if (ctor === undefined || ctor === null)
throw new ERR_INVALID_ARG_TYPE('ctor', 'Function', ctor);
if (superCtor === undefined || superCtor === null)
throw new ERR_INVALID_ARG_TYPE('superCtor', 'Function', superCtor);
if (superCtor.prototype === undefined) {
throw new ERR_INVALID_ARG_TYPE('superCtor.prototype',
'Object', superCtor.prototype);
}
Object.defineProperty(ctor, 'super_', {
value: superCtor,
writable: true,
configurable: true
});
Object.setPrototypeOf(ctor.prototype, superCtor.prototype);
}
ES6
изextends
изES5
реализация версии
понялES6 extends
Какие операции и настройки наследуются__proto__
После точки знаний поставьте вышеуказанноеES6
использование примераES5
легче реализовать, т.Реализация паразитного композиционного наследования, упрощенный код:
// ES5 实现ES6 extends的例子
function Parent(name){
this.name = name;
}
Parent.sayHello = function(){
console.log('hello');
}
Parent.prototype.sayName = function(){
console.log('my name is ' + this.name);
return this.name;
}
function Child(name, age){
// 相当于super
Parent.call(this, name);
this.age = age;
}
// new
function object(){
function F() {}
F.prototype = proto;
return new F();
}
function _inherits(Child, Parent){
// Object.create
Child.prototype = Object.create(Parent.prototype);
// __proto__
// Child.prototype.__proto__ = Parent.prototype;
Child.prototype.constructor = Child;
// ES6
// Object.setPrototypeOf(Child, Parent);
// __proto__
Child.__proto__ = Parent;
}
_inherits(Child, Parent);
Child.prototype.sayAge = function(){
console.log('my age is ' + this.age);
return this.age;
}
var parent = new Parent('Parent');
var child = new Child('Child', 18);
console.log('parent: ', parent); // parent: Parent {name: "Parent"}
Parent.sayHello(); // hello
parent.sayName(); // my name is Parent
console.log('child: ', child); // child: Child {name: "Child", age: 18}
Child.sayHello(); // hello
child.sayName(); // my name is Child
child.sayAge(); // my age is 18
Мы можем поставить вышеES6的例子
пройти черезbabeljs
перекодировано вES5
Посмотрим, более строгая реализация.
// 对转换后的代码进行了简要的注释
"use strict";
// 主要是对当前环境支持Symbol和不支持Symbol的typeof处理
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function _typeof(obj) {
return typeof obj;
};
} else {
_typeof = function _typeof(obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
// _possibleConstructorReturn 判断Parent。call(this, name)函数返回值 是否为null或者函数或者对象。
function _possibleConstructorReturn(self, call) {
if (call && (_typeof(call) === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
// 如何 self 是void 0 (undefined) 则报错
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
// 获取__proto__
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
// 寄生组合式继承的核心
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
// Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
// 也就是说执行后 subClass.prototype.__proto__ === superClass.prototype; 这条语句为true
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
// 设置__proto__
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
// instanceof操作符包含对Symbol的处理
function _instanceof(left, right) {
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
return right[Symbol.hasInstance](left);
} else {
return left instanceof right;
}
}
function _classCallCheck(instance, Constructor) {
if (!_instanceof(instance, Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
// 按照它们的属性描述符 把方法和静态属性赋值到构造函数的prototype和构造器函数上
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
// 把方法和静态属性赋值到构造函数的prototype和构造器函数上
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
// ES6
var Parent = function () {
function Parent(name) {
_classCallCheck(this, Parent);
this.name = name;
}
_createClass(Parent, [{
key: "sayName",
value: function sayName() {
console.log('my name is ' + this.name);
return this.name;
}
}], [{
key: "sayHello",
value: function sayHello() {
console.log('hello');
}
}]);
return Parent;
}();
var Child = function (_Parent) {
_inherits(Child, _Parent);
function Child(name, age) {
var _this;
_classCallCheck(this, Child);
// Child.__proto__ => Parent
// 所以也就是相当于Parent.call(this, name); 是super(name)的一种转换
// _possibleConstructorReturn 判断Parent.call(this, name)函数返回值 是否为null或者函数或者对象。
_this = _possibleConstructorReturn(this, _getPrototypeOf(Child).call(this, name));
_this.age = age;
return _this;
}
_createClass(Child, [{
key: "sayAge",
value: function sayAge() {
console.log('my age is ' + this.age);
return this.age;
}
}]);
return Child;
}(Parent);
var parent = new Parent('Parent');
var child = new Child('Child', 18);
console.log('parent: ', parent); // parent: Parent {name: "Parent"}
Parent.sayHello(); // hello
parent.sayName(); // my name is Parent
console.log('child: ', child); // child: Child {name: "Child", age: 18}
Child.sayHello(); // hello
child.sayName(); // my name is Child
child.sayAge(); // my age is 18
Если вы еще мало знаете о наследовании JS, рекомендуется прочитать соответствующие главы следующих книг, и вы можете найти соответствующиеpdf
Версия.
Рекомендуем прочитать главы книги, связанные с наследованием JS
«Расширенное программирование на JavaScript, 3-е издание» — глава 6, объектно-ориентированное программирование, 6 схем наследования, а именно наследование цепочки прототипов, наследование заимствованного конструктора, наследование композиции, наследование прототипов, паразитное наследование и паразитное композиционное наследование.Адрес книги сообщества Тьюринга, опубликовано позжеgithub
Ссылки, которые содержат эти унаследованные кодыdemo
.
«Объектно-ориентированное программирование JavaScript, 2-е издание» — Глава 6 Наследование, 12 видов схем наследования. 1. Метод цепочки прототипов (традиция имитации), 2. Только наследование прототипа, 3. Метод временного конструктора, 4. Метод копирования атрибутов прототипа, 5. Метод полного копирования атрибутов (т.е. метод поверхностного копирования), 6. Метод глубокого копирования, 7. Наследование прототипа, 8. Режим расширения и улучшения, 9. Множественное наследование, 10. Паразитическое наследование, 11. Заимствование конструктора, 12. Заимствование конструктора и копирование атрибутов.
Введение в стандарт ES6 — Глава 21. Наследование классов
«Глубокое пониманиеES6
- Глава 9 JavaScript
класс в
"Что ты не знаешьJavaScript
-Том 1, Глава 6 Поведенческое делегирование и Приложение AES6中的class
Суммировать
Наследование для JS означает методы, свойства, статические методы и т. д., принадлежащие родительскому классу, и дочерний класс также должен иметь это. В подклассе для поиска можно использовать цепочку прототипов, также можно вызвать родительский класс в подклассе или скопировать копию из родительского класса в подкласс. Методов наследования может быть много, ключ в том, чтобы понимать и быть знакомым с ними. Зная, как работают эти объекты, прототипы и конструкторы, остальное несложно.Паразитическая композиционная наследственностьЕго больше используют разработчики. Рассмотрите паразитарное композиционное наследование. Есть три основных момента:
-
- конструктор подкласса
__proto__
Укажите на конструктор родительского класса, наследуйте статический метод родительского класса
- конструктор подкласса
-
- конструктор подкласса
prototype
из__proto__
в конструктор родительского классаprototype
, наследует метод родительского класса.
- конструктор подкласса
-
- Конструктор родительского класса вызывается в конструкторе дочернего класса для наследования свойств родительского класса.
На этом статья в основном закончена. Ресурсы, такие как код статьи и изображения, размещаются здесьgithub inhertа такжеdemo
экспонатes6-extends
, в сочетании сconsole、source
Панельный обзор лучше.
Читатели, которые находят что-то неправильным или могут быть улучшены, могут оставить комментарий. Кроме того, если вы считаете, что написано хорошо, вы можете поставить лайк, прокомментировать и переслать, что также является своего рода поддержкой для автора.
Избранные статьи автора
Изучите общую архитектуру исходного кода sentry и создайте собственный SDK для мониторинга исключений переднего плана.
Изучите общую архитектуру исходного кода lodash и создайте собственную библиотеку классов функционального программирования.
Изучите общую архитектуру исходного кода подчеркивания и создайте собственную библиотеку классов функционального программирования.
Изучите общую архитектуру исходного кода jQuery и создайте собственную библиотеку js.
Интервьюер спросил: наследование JS
Интервьюер спросил: этот пункт JS
Интервьюер спросил: Могу ли я смоделировать вызов и применить методы JS?
Интервьюер спросил: Могу ли я смоделировать метод привязки, реализующий JS?
Интервьюер спросил: Могу ли я смоделировать новый оператор, реализующий JS?
Внешний интерфейс использует сканер puppeteer для создания PDF-файла «React.js Book» и его слияния.
о
Автор: Чанг ИВакагаваНазвание смешано в реках и озерах. По дороге на фронт | Энтузиасты РРТ | Знаю очень мало, только хорошо учусь.
личный блог
segmentfault
Столбец переднего видения, открылПередний планКолонка, добро пожаловать на внимание ~
Колонка самородков, добро пожаловать, обратите внимание~
Знайте переднюю колонку видения, открылПередний планКолонка, добро пожаловать на внимание ~
github blog, спроситьstar
^_^~
Публичный аккаунт WeChat Ruochuan Vision
Может быть более интересным общедоступный аккаунт WeChat, нажмите и удерживайте, чтобы отсканировать код, чтобы следовать. Вы также можете добавить WeChatruochuan12
, укажите источник и втяните вас в [Front-end Vision Exchange Group].