我是从 Python 和 Smalltalk 的背景转到 Javascript 的,我很欣赏这门语言中 Self 和 Lisp 的传承。使用 ECMAScript5,我想在没有 new 运算符的情况下尝试原型(prototype) 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;
}
它似乎在一个简单的模型中工作:
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))
我是否在实现过程中忽略了原型(prototype) OO 所需的功能?是否有我应该更改的 Javascript 约定或交互?总之,这里的“问题”是什么,是否有明显的改进之处?
我想成为构造函数定义的 DRYer,但我发现函数的名称属性不可写,而这正是支持 WebKit Inspector 的对象名称的原因。我能够构建一个 eval 来完成我想要的,但是......糟糕。
最佳答案
编辑:哦,我现在明白问题了。答:不,你完全正确。设置函数名称的唯一方法是在使用函数声明时,这意味着在评估时。因此,您需要在源代码中包含它(eval 是后门)。我之前回答了一个更简单的问题,但要点相同:Minor drawback with 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
这里是 chromium 问题,讨论了为什么它还没有实现: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;
}
另一个是创建用于 libffi (node-ffi) 的结构。本质上,您同时拥有构造函数继承和原型(prototype)继承。您创建的构造函数继承自构造函数,后者创建结构的实例。 https://github.com/Benvie/node-ffi-tools/blob/master/lib/Struct.js
为了创建一个命名函数,需要使用 eval,所以如果您需要一个命名构造函数,那就是这样。我毫不犹豫地在需要的地方使用它。
关于javascript - 带有 Object.create 和命名构造函数的原型(prototype) OO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9491300/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我正在尝试用ruby中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?
我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use
如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只
我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty