如何在Javascript(OOP)中直接执行继承链的基类?
P粉718165540
P粉718165540 2024-01-10 17:20:07
0
1
406

我正在处理 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我想用一些预定义的 elcontent 等在他们自己的 .render() 方法中覆盖它,但是如果我尝试执行 renderer.render() 方法来自 Renderer 内部,它遍历整个链,我的参数丢失了,因为在 MailboxInbox 中,渲染方法当前没有'不接受任何参数,所以我要么应该让它接受参数并将它们传递到整个链,要么只是在 Renderer 中定义一些专用类,如 baseRender 并直接调用它< /p>

P粉718165540
P粉718165540

全部回复(1)
P粉618358260

从技术上讲,您可以将 this.render(el, text); 替换为

Renderer.prototype.render.call(this, el, text);

它绕过了继承的属性查找。然而,这通常不是一个好的做法,会丧失class继承的优势。

幸运的是,您已经确定了更新中的实际问题:

这确实错误地覆盖了具有不兼容签名的方法,违反了里氏替换原则

您也已经确定了潜在的解决方案:

两个都很好。在后者中,我建议不要命名方法 renderbaseRender,而是推荐类似 renderContent(el, content)renderDefault (el),它们的签名实际上不同 - 并且都可以被覆盖。然而,看看使用两个参数调用时 render 的实现,在我看来,除了调用 el.appendChild(content) 之外,它实际上没有做任何有用的事情,所以我'宁愿完全放弃它并只调用 appendChild (除非您需要覆盖具体行为的能力,例如通过执行 el.prepend(content) 来代替)。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板