所以我目前正在构建一个相当大的框架,用于许多网络项目。我很乐意针对以下场景获得一些建议或最佳实践。
我在网络应用程序中有不同的章节。一次只能看到一章。
函数createView()
在第一次访问章节时被调用。它通过 Handlebars 模板创建 View ,插入 XML 文档中的所有副本(我们为每种语言都有一个 XML),并通过 start()
函数开始章节。每当再次访问章节时都会调用 start()
。它只是将 View 插入到 DOM 中并启用所有功能,如点击事件、其他模块(图库、 slider 等)等。
var Chapter = function(name) {
this.name = name;
this.createView();
};
Chapter.prototype.createView = function() {
var self = this;
// get handlebars template
this.template = config.app.getTemplate('chapters/'+self.name).then(function(hbs) {
// compile hbs template, insert data here - if there is any
var html = hbs();
// save jQuery collection of HTML as view
self.view = $(html);
// insert copy from XML doc
self.view.find('[data-text]').each(function() {
var theID = '#'+$(this).attr('data-text');
var theText = config.xml.find(theID).text();
$(this).html(theText);
});
// start the experience
self.start();
});
};
Chapter.prototype.start = function() {
// stop active experience
if(config.experiences.active) {
config.experiences.active.stop();
}
// scroll to top
$(window).scrollTop(0);
// save this chapter as the active one
config.experiences.active = this;
// insert view into DOM
this.view.appendTo($('main'));
// enable functionality
this.initModules();
this.initNavigation();
this.initLocking();
};
现在,Chapter
的每个实例都需要一些自定义函数,因为每个章节在许多项目中看起来都不同。但我不确定这是否是最好的方法:
在 initCustoms
中使用大量 if-else。
Chapter.prototype.start = function() {
...
this.initCustoms();
};
Chapter.prototype.initCustoms = function() {
if(this.name === 'Fire and Ice') {
// do abc
} else if(this.name === 'Second Sons') {
// do xyz
}
};
那么添加一堆 if-else 语句真的是正确的方法吗?看起来很……肮脏。 我还想:
为自定义章节创建一个对象并继承其原型(prototype)
var FireAndIce = function() {
// do abc
}
FireAndIce.prototype = Chapter.prototype;
FireAndIce.prototype.constructor = Chapter;
Chapter.prototype.start = function() {
...
this.initCustoms();
};
Chapter.prototype.initCustoms = function() {
if(this.name === 'Fire and Ice') {
// inherit functionality of FireAndIce. Can't post it here as I have not been able to do this properly.
}
...
};
但这只会导致继承问题,更改其他实例或主 Chapter
原型(prototype)。我不想将 FireAndIce
的所有功能复制到实例,并且根据我对此主题的研究,我无法正确地从原型(prototype)继承(FireAndIce
)到另一个原型(prototype)的实例(章节
)。
另外,出于好奇,以下是一个坏主意吗?
通过 jQuery 创建自定义 start
事件,我可以根据需要绑定(bind)任意数量的自定义处理程序
Chapter.prototype.start = function() {
...
this.initCustoms();
this.trigger('start');
};
Chapter.prototype.initCustoms = function() {
if(this.name === 'Fire and Ice') {
this.on('start', function() {
// do abc
});
}
...
};
抛开我这样做的原因不谈,这有什么问题吗?我有点喜欢为每一章提供一个 start
和 stop
事件的想法,我可以从任何地方绑定(bind)附加功能。
提前感谢您的建议。
最佳答案
几个选项:
只需为它们分配一个函数
听起来好像只有几个 Chapter
实例,并且每一章都是一次性的(FireAndIce
章节只有一个副本),对于实例。在这种情况下,您只需创建章节实例,然后在创建它们后分配它们的 initCustoms
函数:
var fireAndIce = new Chapter();
fireAndIce.initCustoms = function() {
// stuff for Fire and Ice
};
var secondSons = new Chapter();
secondSons.initCustoms = function() {
// stuff for Second Sons
};
// ...
使用原型(prototype)继承和构造函数
但是如果您想通过继承来做到这一点,则如下所示:
function Chapter() {
}
Chapter.prototype.setup = function() {
// ...chapter common stuff
};
function FireAndIce() {
Chapter.apply(this, arguments); // Chain to parent constructor
// ...fire and ice stuff
}
FireAndIce.prototype = Object.create(Chapter.prototype);
FireAndIce.prototype.constructor = FireAndIce
FireAndIce.prototype.initCustoms = function() {
// ...Fire and Ice custom stuff
};
function SecondSons() {
Chapter.apply(this, arguments); // Chain to parent constructor
// ...Second Sons stuff
}
SecondSons.prototype = Object.create(Chapter.prototype);
SecondSons.prototype.constructor = SecondSons
SecondSons.prototype.initCustoms = function() {
// ...Second Sons custom stuff
};
这样,FireAndIce
实例就可以共享其原型(prototype)上的 initCustoms
,并且还可以共享 Chapter
原型(prototype)上的所有内容,因为 Chapter.prototype
是 FireAndIce.prototype
对象背后的原型(prototype)。 (SecondSons
也类似。)
请注意,如果派生函数(FireAndIce
、SecondSons
)和 Chapter
具有不同的参数列表,则不要将所有参数传递给 Chapter
来自派生函数,您可以只传递适当的内容:
Chapter.call(this, the, appropriate, args, go, here);
使用原型(prototype)继承,不使用构造函数
有些人更喜欢使用没有构造函数的原型(prototype)继承,因此不使用 new
。这也是一个选择:
var ChapterProto = {
setup: function() {
// ...common chapter stuff...
}
};
function createChapter() {
var rv = Object.create(ChapterProto);
// ...common chapter stuff...
return rv;
}
var FireAndIceProto = Object.create(ChapterProto);
FireAndIceProto.initCustoms = function() {
// ...Fire and Ice custom stuff...
};
function createFireAndIce() {
var rv = Object.create(FireAndIceProto);
createChapter.apply(rv, arguments);
// ...Fire and Ice stuff...
return rv;
}
var SecondSonsProto = Object.create(SecondSonsProto);
SecondSonsProto.initCustoms = function() {
// ...Second Sons custom stuff...
};
function createSecondSons() {
var rv = Object.create(SecondSonsProto);
createChapter.apply(rv, arguments);
// ...Second Sons stuff...
return rv;
}
同样,如果参数列表不同,您可以使用 .call
而不是 .apply
。
结论
对于少数对象,我更愿意在创建实例后为其分配函数。代码更少,更简单。
但是对于对象的类(小写意义上的),我会使用带有构造函数的原型(prototype)继承,如上所述(但其他一些人会在没有构造函数的情况下使用它)。
<小时/>上面使用了 Object.create
,它是 ES5 中的新功能(现在大约有五年了)。如果您需要支持非常旧的引擎,您可以填充上面使用的单参数版本(第二个参数不能在 ES3 引擎上填充):
if (!Object.create) {
Object.create = function(proto, props) {
if (props) {
throw "The second argument to Object.create cannot be polyfilled.";
}
function ctor() {
}
ctor.prototype = proto;
return new ctor();
};
}
关于javascript - 特定对象实例的自定义函数 - 我有什么可能性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26929553/