因此,我正在构建一个非常大的框架,用于许多Web项目。我很乐意为以下场景提供一些建议或最佳实践。
我在网络应用中有不同的章节。一次只能看到一章。
第一次访问章节时调用函数createView()
。它通过把手模板创建视图,插入XML文档中的所有副本(我们有每种语言的XML),并通过start()
函数启动章节。每当再次访问章节时,都会调用start()
。它只是将视图插入DOM并启用所有功能,如点击事件,其他模块(画廊,滑块等)。
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
中使用lof of 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语句真的要走了吗?看起来好像......很脏。 我也想说:
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
原型。我不想将FireAndIce
的所有功能复制到实例上,根据我对此主题的研究,我无法正确地从原型(FireAndIce
)继承到另一个实例原型(Chapter
)。
另外,出于好奇,以下是一个坏主意?
start
事件,我可以根据需要绑定多个自定义处理程序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
事件,我可以从中处理其他功能。
提前感谢您的建议。
答案 0 :(得分:1)
有两种选择:
听起来似乎只有少数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
};
// ...
但是如果你想通过继承来做这件事,那么看起来如何:
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
个实例在原型上共享initCustoms
,并在Chapter
原型上共享所有内容,因为Chapter.prototype
是FireAndIce.prototype
背后的原型1}}对象。 (同样适用于SecondSons
。)
请注意,如果派生函数(FireAndIce
,SecondSons
)和Chapter
具有不同的参数列表,而不是将所有参数传递给派生函数的Chapter
,可以通过合适的方式:
Chapter.call(this, the, appropriate, args, go, here);
有些人更喜欢在没有构造函数的情况下使用原型继承,因此不使用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
。
对于少数几个对象,我宁愿在创建实例后只为它们分配函数。更少的代码,更简单。
但是对于对象的类(在小写意义上),我使用原型继承和上面的构造函数(但是其他一些人在没有构造函数的情况下使用它)。 / p>
以上使用Object.create
,这是ES5的新功能(现在大约五年)。如果你需要支持真正的旧引擎,你可以填充上面使用的单参数版本(第二个参数不能在ES3引擎上进行polyfilled):
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();
};
}