Я перешел к Javascript, имея опыт работы с Python и Smalltalk, и я ценю родословную Self и Lisp в этом языке. С ECMAScript5 я хотел попробовать свои силы в прототипном объектно-ориентированном программировании без нового оператора.
Ограничения:
- необязательный новый оператор для создания классов
- цепочка прототипов должна быть правильной для instanceof
- именованные конструкторы для поддержки отладки WebInspector
- alloc().init() последовательность создания, такая как Objective-C и Python
Вот моя попытка реализации, чтобы соответствовать критериям:
function subclass(Class, Base) {
"use strict";
function create(self, args) {
if (!(self instanceof this))
self = Object.create(this.prototype);
var init = self.__init__;
return init ? init.apply(self, args) : self;
}
if (Base instanceof Function) Base = Base.prototype;
else if (Base===undefined) Base = Object.prototype;
Class.prototype = Object.create(Base);
Class.prototype.constructor = Class;
Class.create = create;
Class.define = function define(name, fn) { return Class.prototype[name] = fn; };
Class.define('__name__', Class.name);
return Class;
}
И, похоже, это работает в простом макете:
function Family(){return Family.create(this, arguments)}
subclass(Family, Object);
Family.define('__init__', function __init__(n){this.name=n; return this;});
function Tribe(){return Tribe.create(this, arguments)}
subclass(Tribe, Family);
function Genus(){return Genus.create(this, arguments)}
subclass(Genus, Tribe);
function Species(){return Species.create(this, arguments)}
subclass(Species, Genus);
Использование класса в качестве фабричной функции:
var dog = Species('dog');
console.assert(dog instanceof Object);
console.assert(dog instanceof Family);
console.assert(dog instanceof Tribe);
console.assert(dog instanceof Genus);
console.assert(dog instanceof Species);
Или используя новый оператор:
var cat = new Species('cat');
console.assert(cat instanceof Object);
console.assert(cat instanceof Family);
console.assert(cat instanceof Tribe);
console.assert(cat instanceof Genus);
console.assert(cat instanceof Species);
console.assert(Object.getPrototypeOf(dog) === Object.getPrototypeOf(cat))
Не упустил ли я из своей реализации необходимые функции прототипа ООП? Существуют ли соглашения или взаимодействия Javascript, для которых я должен внести изменения? Подводя итог, скажите, какие здесь «подводные камни» и есть ли очевидные улучшения?
Я хотел быть DRYer с определениями конструктора, но обнаружил, что свойство name функции недоступно для записи, и именно это поддерживает имена объектов WebKit Inspector. Я смог построить eval, чтобы выполнить то, что хотел, но... фу.
/\w+/
, чтобы убедиться, что это только допустимое имя метода. Но это похоже на использование кувалды для установки гвоздя — было бы намного элегантнее, если бы было разрешено устанавливать свойство имени функции. В конце концов, Javascript — это язык-прототип... - person Shane Holloway   schedule 02.03.2012