我正在處理 3 個可擴展類別的繼承鏈。
渲染器(基礎)-> Mailbox(子級)-> MailboxInbox(最終子級)
它們每個都有自己的render
方法。孩子只是重寫渲染器(基礎)render
方法最後他們無論如何應該使用渲染器的render
方法(Base< /strong>) 類。我的問題是,當我在Renderer 類別(createElementWithTextInside) 中執行某些方法時,它並沒有完全執行Renderer 的render 方法(Renderer . render()),但它是從可擴展類別鏈的末尾開始的。例如,它開始遍歷:
1 - MailboxInbox.render
#
2 - Mailbox.render
3 - Renderer.render
我了解 js 類別/繼承在幕後是如何運作的。 Javascript 只是擴展物件原型,腳本會遍歷它們等。但我的問題是:如何避免這種行為並在需要時直接呼叫其方法中的 Renderer.render 方法?
我無法在渲染器中儲存__self,因為它無論如何都會指向目前實例(MailboxInbox)的this
。另外,我無法使用 .bind/lambda (箭頭函數),因為我需要保存上下文
小提琴
class Renderer { get noResultContent() { const p = this.createElement('p', 'no-result-msg'); const textNode = document.createTextNode('No result'); p.appendChild(textNode); return p; }; createElement(tag, className) { if (!tag) throw new Error('Tag must be passed!'); const res = document.createElement(tag); res.classList.add(className); return res; } createTextNode(text) { const res = document.createTextNode(text); return res; } /** * automatically creates an el based on tag, text node and insert the text node into the el */ createElementWithTextInside(tag, className, content) { const el = this.createElement(tag, className); const text = this.createTextNode(content); this.render(el, text); return el; } checkIfDomEl = el => el instanceof Element; render(el, content) { console.log('3: RENDERER RENDER') if (!this.checkIfDomEl(el)) throw new Error(`Please, pass the valid DOM el. Received: ${el}, ${typeof el} `); const finalContent = content || this.noResultContent; el.appendChild(finalContent); } } -------- class Mailbox extends Renderer { rootEl; constructor(selector) { super(); this.rootEl = document.querySelector(selector); } renderTitle(content) { if (!content) return null; const titleEl = super.createElementWithTextInside('h3', 'mailbox-title', content) super.render(this.rootEl, titleEl); } render() { console.log('2: MAILBOX RENDER') super.render(this.rootEl); } } -------- class MailboxInbox extends Mailbox { title = "Inbox" constructor(params) { const { selector } = params; super(selector); } renderTitle() { super.renderTitle(this.title); } render() { console.log('1: INBOX RENDER') super.render(); } } -------- const inbox = new MailboxInbox({selector: '#container'}); inbox.renderTitle()
這裡它只是在控制台中呈現:
#1:收件匣渲染
# 2:郵箱渲染
3:渲染器渲染
感謝您的幫忙! 親切的問候!
更新
#
基本上我只是想有一個基本的render
類,它可以接受參數:(el,content)
(內容是可選的)和Children我想用一些預先定義的el
和content
等在他們自己的.render()
方法中覆寫它,但是如果我嘗試執行renderer .render()
方法來自Renderer 內部,它遍歷整個鏈,我的參數丟失了,因為在MailboxInbox 中,渲染方法當前沒有'不接受任何參數,所以我要么應該讓它接受參數並將它們傳遞到整個鏈,要么只是在Renderer 中定義一些專用類,如baseRender
並直接調用它< /p>
從技術上講,您可以將
this.render(el, text);
替換為它繞過了繼承的屬性查找。然而,這通常不是一個好的做法,會喪失
class
繼承的優勢。幸運的是,您已經確定了更新中的實際問題:
這確實錯誤地覆蓋了具有不相容簽名的方法,違反了里氏替換原則。
您也已經確定了潛在的解決方案:
兩個都很好。在後者中,我建議不要命名方法
render
和baseRender
,而是推薦類似renderContent(el, content)
和renderDefault (el)
,它們的簽名實際上不同- 並且都可以被覆蓋。然而,看看使用兩個參數呼叫時render
的實現,在我看來,除了呼叫el.appendChild(content)
之外,它實際上沒有做任何有用的事情,所以我'寧願完全放棄它並只調用appendChild
(除非您需要覆蓋具體行為的能力,例如通過執行el.prepend(content)
來代替)。