【发布时间】:2013-11-13 15:19:35
【问题描述】:
拥有 Java 背景,当我切换到 Javascript 时,我(懒惰地)尝试坚持我对 oop 的了解,即经典继承。我正在开发一个网络应用程序(我制作的),并使用了这种继承。但是,我正在考虑更改我的代码并重写 OOP 部分以进行原型继承(两个原因:我读了很多,它更好,其次,我需要尝试另一种方式以便更好地理解它)。
我的应用创建数据可视化(使用 D3js,但这不是主题),并以这种方式组织我的代码:
function SVGBuilder( dataset ) {
this.data = dataset;
this.xCoord;
this.startDisplaying = function() {
// stuff
this.displayElement();
}
}
displayElement() 方法在继承自 SVGBuilder(或多或少是一个抽象类)的“类”中定义。然后我有:
function SpiralBuilder( dataset ) {
SVGBuilder.call( this, dataset );
this.displayElement = function() {
// stuff
};
}
SpiralBuilder.inheritsFrom( SVGBuilder );
我还有其他几个基于相同结构的“构建器”。
调用构建器的脚本如下所示(有点复杂,因为它根据用户输入选择正确的构造器):
var builder = new SpiralBuilder( data );
builder.startDisplaying();
现在是“转换部分”。从Douglas Crockford's article 到 Eloquent Javascript 的部分内容,我阅读了很多关于此的内容。在Aadit M Shah 的comment 中,他提出了一个如下所示的结构:
var svgBuilder = {
data: [],
xCoord: 0, // ?
create: function( dataset ) {
var svgBuilder= Object.create(this);
svgBuilder.data = dataset;
return svgBuilder;
},
startDisplaying: function() {
// stuff
}
}
但是,在这一点上,我被困住了。首先(技术问题),我可以声明变量(数据,xCoord)而不用这种模式初始化它们吗?就像this.data;?其次,我应该如何创建继承?我只是手动把相应的功能放在原型里?比如:
var spiralBuilder = builder.create( dataset );
spiralBuilder.prototype.displayElements = function() {
// Code to display the elements of a spiral
};
spiralBuilder.displayElements();
如果我是正确的,这意味着在调用构建器的脚本中,我必须在单个构建器的原型中添加/修改方法,而不是选择正确的构造函数(它将不再存在)实例。事情应该怎么做?
或者我应该尝试以完全不同的方式设计我的代码?如果是这样,您能给我一些建议/参考吗?
【问题讨论】:
-
在 svgBuilder 中,成员 xCoord 建议这应该是一个实例成员(对于您创建的每个实例都是唯一的),但它会将其添加到原型上以便共享。如果此成员是原始成员(数字、字符串、布尔值),那么它是不可变的,您只能通过重新分配来更改它,因此它基本上会创建一个额外的无价值变量。如果这个成员是一个数组,那么你就有麻烦了
aInstance.someArray.push("fromA");bInstance.someArray 将是["fromA"] -
那里有一些构建器和辅助函数,因此您可以在创建实例时混合继承。这种方式违背了 OOP 的观点,因为当某些事情发生变化时,您的代码中有很多点需要在您的对象发生变化时进行查看。如果您了解构造函数的基础知识,那么使用工厂方法可能比让创建实例的代码决定对象是什么更好。我已经更新了我的答案,以解决您关于 svgBuilder 中实例变量的问题。
标签: javascript oop language-design prototype-programming