Мне самому было любопытно, и я не мог найти быстрого ответа, поэтому вот моя разбивка:
Что он делает
__extends — это функция, которая имитирует наследование одного класса в объектно-ориентированных языках и возвращает новую функцию-конструктор для производной функции, которая может создавать объекты, наследуемые от базового объекта.
Примечание 1:
На самом деле я сам не знал об этом, но если вы сделаете что-то вроде следующего, где все значения верны, переменной будет присвоено значение последнего тестируемого элемента, если только один из них не является ложным, и в этом случае переменная устанавливается в значение false:
// value1 is a function with the definition function() {}
var value1 = true && true && function() {};
// value2 is false
var value2 = true && false && function() {};
// value3 is true
var value3 = true && function() {} && true;
Я упоминаю об этом, потому что это то, что больше всего смутило меня, когда я увидел этот javascript, и он использовался пару раз в определении функции __extends.
Примечание 2. Параметр d (вероятно, означает производный) и параметр b (вероятно, означает базовый) являются функциями-конструкторами, а не объектами-экземплярами.
Примечание 3:
prototype
— это свойство функции и объект-прототип, используемый функциями «конструктора» (то есть объектами, созданными с использованием new <function name>()
).
Когда вы используете оператор new
для создания нового объекта, внутреннее [[PROTOTYPE]]
нового объекта, также известное как __proto__
, устанавливается в качестве свойства прототипа функции.
function Person() {
}
// Construct new object
var p = new Person();
// true
console.log(p.__proto__ === Person.prototype);
// true
console.log(Person.prototype.__proto__ === Object.prototype);
Это не копия. Это и есть объект.
Когда вы создаете буквальный объект, например
var o = {};
// true
console.log(o.__proto__ === Object.prototype);
__proto__
нового объекта устанавливается равным Object.prototype
(встроенная функция конструктора объекта).
Вы можете установить __prototype__
объекта на другой объект, используя Object.create
.
Когда свойство или метод не найдены в текущем объекте, проверяется [[PROTOTYPE]]
объекта. Если он не найден, то проверяется прототип ЭТОГО объекта. И так он проверяет прототипы, пока не достигнет конечного объекта-прототипа, Object.prototype
. Имейте в виду, ничто не является копией.
Примечание 4 При моделировании наследования в Javascript устанавливаются прототипы функций-конструкторов.
function Girl() {
}
Girl.prototype = Object.create(Person.prototype);
// true
console.log(Girl.prototype.__proto__ === Person.prototype);
// true
console.log(Girl.constructor === Function);
// Best practices say reset the constructor to be itself
Girl.constructor = Girl;
// points to Girl function
console.log(Girl.constructor);
Обратите внимание, как мы указываем конструктору Girl, потому что конструктор Person указывает на встроенный Function
.
Вы можете увидеть приведенный выше код в действии по адресу: http://jsbin.com/dutojo/1/edit?js,console
Оригинал:
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Разбивка:
var __extends = (this && this.__extends) || (function () {
// gobbledygook
})();
Помня о моем Примечании 1 выше, эта первая часть (и конец) создает переменную с именем __extends, предназначенную для удержания функции для установки прототипа производного учебный класс.
(this && this.__extends)
делает то, что объясняет мое Примечание 1. Если this соответствует действительности и this.__extends соответствует действительности, то переменная __extends уже существует и поэтому устанавливается в существующий экземпляр самой себя. Если нет, то устанавливается то, что идет после || который является iife (немедленно вызываемым функциональным выражением).
А теперь тарабарщина, которая является фактическим определением __extends:
var extendStatics = Object.setPrototypeOf ||
Переменной с именем extendStatics присваивается либо встроенная функция Object.setPrototypeOf среды, в которой выполняется скрипт (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf а>)
ИЛИ
он создает свою версию
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
В Примечании 3 я обсуждал __proto__
, также известный как [[PROTOTYPE]]
, и то, как его можно установить. Код
{ __proto__: [] } instanceof Array
— это тест, позволяющий определить, позволяет ли текущая среда установить это свойство, путем сравнения набора __proto__
литерального объекта с литеральным массивом с помощью встроенной функции Array.
Возвращаясь к моему Примечанию 1 выше и помня, что оператор instanceof javascript возвращает значение true или false (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof), если среда оценивает объект с его свойством прототипа, установленным на встроенный массив, тогда для extendsStatics установлено значение
function (d, b) { d.__proto__ = b; })
Если среда не оценивает это таким образом, тогда для параметра extendStatics установлено следующее:
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }
Это происходит потому, что __proto__
никогда не входил в официальный стандарт ECMAScript до ECMAScript 2015 (и согласно https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto) только для обратной совместимости). Если это поддерживается, используется функция __proto__
, иначе используется версия «свернуть свою собственную», которая выполняет копирование из объекта b в d для определенных пользователем свойств.
Теперь, когда функциональная переменная extendStatics определена, возвращается функция, которая вызывает все, что находится внутри extendStatics (а также некоторые другие вещи). Обратите внимание, что параметр «d» — это подкласс (тот, который наследуется), а «b» — это суперкласс (тот, от которого наследуется):
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
Разбивая его на части, вызывается метод extendStatics, и прототип первого объекта параметра (d) имеет значение (b) (вспомните Примечание 3 выше):
extendStatics(d, b);
В следующей строке объявляется функция-конструктор с именем '__', которая присваивает своему конструктору производную (d) функцию-конструктор:
function __() { this.constructor = d; }
если базовая (b) функция constructor
окажется нулевой, это гарантирует, что производная функция сохранит свою собственную prototype
.
Из https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor, Object.prototype.constructor (все объекты являются объектами в javascript):
Возвращает ссылку на функцию конструктора объекта, которая создала экземпляр объекта. Обратите внимание, что значение этого свойства является ссылкой на саму функцию, а не на строку, содержащую имя функции.
А также
Все объекты будут иметь свойство конструктора. Объекты, созданные без явного использования функции-конструктора (то есть литералы объекта и массива), будут иметь свойство конструктора, указывающее на тип конструктора Fundamental Object для этого объекта.
Таким образом, если constructor
функция '__' была обновлена как есть, она создала бы производный объект.
Наконец, есть эта строка:
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
который устанавливает prototype
производного (d) как новый пустой объект, если базовая функция constructor
оказывается нулевой
// b is null here so creates {}
Object.create(b)
OR
устанавливает prototype
функции __ constructor
в качестве базового класса prototype
, а затем вызывает __(), что приводит к установке производных функций constructor
в качестве производных функций.
(__.prototype = b.prototype, new __()
Таким образом, возвращаемая конечная функция создает производную функцию-конструктор, которая прототипически наследуется от базовой функции-конструктора.
Почему функция B() возвращает это?
return _super !== null && _super.apply(this, arguments) || this;
Согласно: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
Метод apply() вызывает функцию с заданным значением this и аргументами, представленными в виде массива (или объекта, подобного массиву).
Помните, что B — это функция-конструктор, и именно это возвращается в определении B.
Если бы у вас был класс Person (функция-конструктор), который принимал параметр имени в функции-конструкторе, вы могли бы вызвать производный класс Girl (функция-конструктор) с именем девушки в качестве параметра.
// Base constructor function
function Person(n) {
// Set parameter n to the name property of a Person
this.name = n;
}
function Girl() {
// Call the Person function with same arguments passed to new Girl
Person.apply(this, arguments);
// Set it so all Girl objects created inherit properties and methods from Person
Girl.prototype = Object.create(Person.prototype);
// Make sure the constructor is not set to Person
Girl.prototype.constructor = Girl;
}
var p = new Person("Sally");
var g = new Girl("Trudy");
console.log(p.name);
console.log(g.name);
person
Mike Cheel
schedule
27.09.2017
class
, вы выбираете объекты на основе классов. Все это необходимо для реализации наследования классов в терминах объектов на основе прототипов. Функция появляется, когда целевая версия JavaScript/ES не имеет встроенной поддержки для них, в противном случае она просто выдаетclass A {}
и так далее. - person Jesper   schedule 30.08.2017super
) и даже разрешено возвращать другой объект в некоторых случаях). Причина, по которой он не выглядит чистым, заключается в том, что это не так — ему приходится подделывать что-то, что еще не встроено в язык для вашей версии. - person Jesper   schedule 30.08.2017class
по-прежнему использует наследование прототипов. - person Bergi   schedule 28.09.2017