我是从 Python 和 Smalltalk 的背景开始接触 Javascript 的,我很欣赏 Self 和 Lisp 在语言中的传承。使用 ECMAScript5,我想在没有 new 运算符的情况下尝试原型 OO。
约束:
- 用于创建类的可选 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);
或使用 new 运算符:
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))
我是否在我的实现中忽略了原型 OO 所需的功能?是否有我应该更改的 Javascript 约定或交互?总之,这里的“陷阱”是什么,有什么明显的改进吗?
我想成为具有构造函数定义的 DRYer,但我发现函数的 name 属性不可写,这就是支持 WebKit Inspector 的对象名称的原因。我能够构建一个 eval 来完成我想要的,但是......糟糕。