[英]Doing work in ES6 Class constructors
我正在嘗試使用JavaScript構建文檔索引,並且在弄清楚在es6構造函數中進行工作的正確方法時遇到了麻煩。
我能buildIndex
的唯一解決方案是讓用戶在構造后顯式調用buildIndex
這似乎是直覺和錯誤的,好像我在構造后需要調用“ construct”一樣。
我是否缺少某些東西,或者ES6構造函數受到限制?
class TokenIndex {
constructor(document, stemmer) {
this.document = document;
this.stemmer = stemmer || (x => x);
this._buildIndex();
}
_buildIndex(){
// do expensive index build
}
}
class FilteredTokenIndex extends TokenIndex {
constructor(document, stemmer, filter) {
this.filterRegex = filter;
// Fails because super must be called before `this`
super(document, stemmer);
}
_buildIndex(){
// do expensive index build
}
}
class FilteredTokenIndex2 extends TokenIndex {
constructor(document, stemmer, filter) {
// Fails because builds the index without a filter
super(document, stemmer);
this.filterRegex = filter;
}
_buildIndex(){
// do expensive index build
}
}
基於ES6的解決方案是不要在需要完全初始化派生類的基本構造函數中放置任何內容。 而是將邏輯放在.init()
方法中。
然后,創建一個同時執行new
和.init()
的工廠函數,然后返回一個完整的對象。
class TokenIndex {
constructor(document, stemmer) {
this.document = document;
this.stemmer = stemmer || (x => x);
}
init() {
this._buildIndex();
return this;
}
_buildIndex(){
// do expensive index build
}
}
class FilteredTokenIndex extends TokenIndex {
constructor(document, stemmer, filter) {
super(document, stemmer);
this.filterRegex = filter;
}
_buildIndex(){
// do expensive index build
}
}
// Factory functions that should be exported and made public
// and should be the only way these instances can be created
// by the outside world
createTokenIndex(document, stemmer) {
let obj = new TokenIndex(document, stemmer);
return obj.init();
}
createFilteredTokenIndex(document, stemmer, filter) {
let obj = new FilteredTokenIndex(document, stemmer, filter);
return obj.init();
}
這些工廠函數也可以成為該類的靜態方法,但是我不希望完全不導出該類,因為這會使外部用戶無法使用new
對象實例化它,並且有可能使該對象的初始化混亂。
僅供參考,當您需要在對象的初始化中執行異步操作時,可以使用類似的設計模式。 在那種情況下, .init()
方法返回一個承諾,當所有異步操作完成后,該承諾將解析為對象本身。 然后,工廠函數返回該承諾。 在這兩種情況下都使用工廠函數的優點是,外部世界只有在完全初始化對象之后才能使用它。
不要在構造函數中進行任何工作(尤其是在異步工作時 )。 構造函數應該只初始化實例,別無其他。
如果該實例在未完成工作的情況下不可用,則可以在構造之前使用靜態方法進行操作:
class TokenIndex {
constructor(index, document, stemmer) {
this.index = index;
this.document = document;
this.stemmer = stemmer;
}
static buildFrom(document, stemmer = (x => x)) {
// do expensive index build
return new this(/* result of work */, document, stemmer);
}
}
class FilteredTokenIndex extends TokenIndex {
buildFrom(document, filter, stemmer) {
// do expensive index build
return new this(/* result of work */, document, stemmer);
// or if the filtering is just some preprocessing for the index building,
return super.buildFrom(filteredDocument, stemmer);
}
}
我是否缺少某些東西,或者ES6構造函數受到限制?
不,您什么都不丟失。 構造函數不得以任何編程語言調用可重寫方法。
答案似乎是利用new.target來確定這是正在構造的實際類還是父類,並且僅在它們匹配時才執行實際工作。 終於在此mozilla文章中找到了答案:
https://hacks.mozilla.org/2015/08/es6-in-depth-subclassing/
class TokenIndex {
constructor(document, stemmer) {
this.document = document;
this.stemmer = stemmer || (x => x);
if (new.target == TokenIndex){
this._buildIndex();
}
}
_buildIndex(){
console.log('Build TokenIndex') // do expensive index build
}
}
class FilteredTokenIndex extends TokenIndex {
constructor(document, stemmer, filter) {
super(document, stemmer);
this.filterRegex = filter;
if (new.target == FilteredTokenIndex){
this._buildIndex();
}
}
_buildIndex(){
// do expensive index build
console.log('Build FilteredTokenIndex')
}
}
var ti = new TokenIndex(); // prints Build TokenIndex
var fti = new FilteredTokenIndex(); // prints Build FilteredTokenIndex
謝謝
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.