Прототип объектно-ориентированного объекта с Object.create и именованными конструкторами

Я перехожу к Javascript, имея опыт работы с Python и Smalltalk, и я ценю взаимосвязь Self и Lisp в этом языке.С ECMAScript5 я хотел попробовать свои силы в прототипном объектно-ориентированном программировании без оператора new.

Ограничения:

  • необязательный новый оператор для создания классов
  • цепочка прототипов должна быть правильной для именованных конструкторов 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, чтобы выполнить то, что я хотел, но ... фу.

7
задан hippietrail 31 January 2013 в 12:57
поделиться