Sha*_*way 7 javascript oop prototype object-create
我是从Python和Smalltalk的背景来看Javascript,我很欣赏Self和Lisp在语言中的用法.使用ECMAScript5,我想在没有新操作符的情况下尝试使用原型OO.
约束:
以下是我尝试实施以满足标准:
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;
}
Run Code Online (Sandbox Code Playgroud)
它似乎在一个简单的模型中工作:
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);
Run Code Online (Sandbox Code Playgroud)
使用该类作为工厂函数:
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);
Run Code Online (Sandbox Code Playgroud)
或者使用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))
Run Code Online (Sandbox Code Playgroud)
在我的实现中,我是否忽略了原型OO所需的功能?是否有我应该进行更改的Javascript约定或交互?总之,这里有什么"问题",有没有明显的改进?
我希望使用构造函数定义成为DRYer,但我发现函数的name属性不可写,这就是支持WebKit Inspector的对象名称.我能够构建一个eval来完成我想要的东西,但是......哎呀.
小智 9
编辑:哦,我现在看到了这个问题.答:不,你说的完全正确.设置函数名称的唯一方法是使用函数声明,这意味着在评估时.因此,您需要在源代码中使用它(eval是后门).我之前回答了一个更简单的问题,但具有相同的要点:Crockford Prototypical Inheritance的一个小缺点.关于这个主题的另一个资源是http://kangax.github.com/nfe/
有一种运动来使用该displayName
属性,以便将函数的不可更改名称与其调试器外观分开.这是在Firefox和其他一些东西中实现的,并且是一个包含在es6中的稻草人,但尚未成为暂定规范的一部分:http://wiki.ecmascript.org/doku.php?id = strawman:name_property_of_functions
以下是一些关于命名函数主题的Chrome工作人员的论文http://querypoint-debugging.googlecode.com/files/NamingJSFunctions.pdf
以下是铬问题,讨论为什么它还没有实现:http://code.google.com/p/chromium/issues/detail?id = 17356
原来的答案:
你打算完成的任务,你做得很好.我做过类似类型的几个例子:
首先是一个简单的"遗传"功能,它允许你做以下事情:
var MyObjCtor = heritable({
constructor: function MyObj(){ /* ctor stuff */},
super: SomeCtor,
prop1: val,
prop2: val,
/**etc..*/
});
function heritable(definition){
var ctor = definition.constructor;
Object.defineProperty(ctor, 'super', {
value: definition.super,
configurable: true,
writable: true
});
ctor.prototype = Object.create(ctor.super.prototype);
delete definition.super;
Object.keys(definition).forEach(function(prop){
var desc = Object.getOwnPropertyDescriptor(definition, prop);
desc.enumerable = false;
Object.defineProperty(ctor.prototype, prop, desc);
});
function construct(){
var obj = new (ctor.bind.apply(ctor, [].concat.apply([null], arguments)));
ctor.super.call(obj);
return obj;
}
construct.prototype = ctor.prototype;
return construct;
}
Run Code Online (Sandbox Code Playgroud)
另一种是创建用于libffi(node-ffi)的结构.从本质上讲,你有构造函数继承和原型继承.您可以创建从构造函数继承的构造函数,这些构造函数创建结构的实例.https://github.com/Benvie/node-ffi-tools/blob/master/lib/Struct.js
为了创建一个命名函数,需要使用eval,所以如果你需要一个命名的构造函数.我毫不犹豫地在需要的地方使用它.