Ха. Для меня это выглядит намного сложнее, чем должно быть.
На самом деле, присматриваясь, я действительно возражаю против того, что он делает, предоставляя this._super()
в методе для вызова метода суперкласса.
Код вводит зависимость от typeof==='function'
(ненадежный для некоторых объектов), Function#toString
(argh, декомпозиция функции также ненадежна) и решение о том, следует ли выполнять перенос, основываясь на том, использовали ли вы последовательность байтов _super
в теле функции (даже если вы использовали ее только в строке. Если вы попробуете, например, this['_'+'super']
, это не удастся).
И если вы сохраняете свойства в своих функциональных объектах (например, MyClass.myFunction.SOME_PRIVATE_CONSTANT
, что вы можете сделать, чтобы сохранить пространства имен в чистоте), обертывание не даст вам получить эти свойства. И если исключение выдается в методе и перехватывается в другом методе того же объекта, _super
в конечном итоге будет указывать на неправильную вещь.
Все это просто для упрощения вызова метода одного и того же суперкласса. Но я не думаю, что это особенно сложно сделать в JS. Это слишком умно для собственного блага, и в процессе делает все менее надежным. (О, и arguments.callee
недопустим в строгом режиме, хотя на самом деле это не его вина, так как это произошло после того, как он его опубликовал.)
Вот что я сейчас использую для занятий. Я не утверждаю, что это «лучшая» система класса JS, потому что есть загружает различных способов сделать это и множество различных функций, которые вы можете добавить или не добавить. Но он очень легкий и нацелен на то, чтобы быть «JavaScriptic», если это слово. (Это не так.)
Function.prototype.makeSubclass= function() {
function Class() {
if (!(this instanceof Class))
throw 'Constructor function requires new operator';
if ('_init' in this)
this._init.apply(this, arguments);
}
if (this!==Object) {
Function.prototype.makeSubclass.nonconstructor.prototype= this.prototype;
Class.prototype= new Function.prototype.makeSubclass.nonconstructor();
}
return Class;
};
Function.prototype.makeSubclass.nonconstructor= function() {};
Обеспечивает:
защита от случайного пропажи new
. Альтернативой является тихое перенаправление с X()
на new X()
, поэтому пропущенный new
работает. Это бросок, который лучше; Я пошел на явную ошибку, чтобы не привыкать писать без new
и вызывать проблемы на других объектах, не определенных таким образом. В любом случае это лучше, чем недопустимый JS-стандарт, согласно которому свойства this.
попадают в window
и впоследствии загадочно идут не так.
наследуемый _init
метод, поэтому вам не нужно писать функцию-конструктор, которая ничего не делает, кроме как вызывает функцию конструктора суперкласса.
и это действительно все.
Вот как вы можете использовать его для реализации примера Resig:
var Person= Object.makeSubclass();
Person.prototype._init= function(isDancing) {
this.dancing= isDancing;
};
Person.prototype.dance= function() {
return this.dancing;
};
var Ninja = Person.makeSubclass();
Ninja.prototype._init= function() {
Person.prototype._init.call(this, false);
};
Ninja.prototype.swingSword= function() {
return true;
};
var p= new Person(true);
p.dance(); // => true
var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true
// Should all be true
p instanceof Person &&
n instanceof Ninja && n instanceof Person
Вызов суперкласса осуществляется путем конкретного присвоения имени нужному методу и call
его использования, как в Python. Вы можете добавить член _super
в функцию конструктора, если хотите избежать повторного присвоения имени Person
(так вы бы сказали Ninja._super.prototype._init.call
или, возможно, Ninja._base._init.call
).