js类与继承与对象关联风格解读

前言

读完了《你不知的js上卷》后,使用了类与继承与,对象关联风格与行为委托实现一个简单的个人任务管理系统。通过实战后对这两种设计模式有了更加深刻的了解。

代码部分对比

类与继承设计模式

//bulletBox.js
(function(_) {
    var template = 
    `<div class="overlay">
         <div class="box">
            <div class="box-title">
                <h3>消息提醒</h3>
                <div class="box-close icon-cross1"></div>
            </div>
            <div class="box-main">
                <div class="new-title">
                    <h3 class="nameValue">名称:</h3>
                    <input type="text">
                </div>
                <button class="btn2 confirm">确定</button>
                <button class="btn2 cancel">取消</button>
            </div>
        </div> 
    </div>`;
     
    function Modal(options) {
        this.options = options || {}; 
        this.container = this.layout.cloneNode(true);
        
        this.body = this.container.querySelector('.new-title');
        this.bodyContent = this.container.querySelector('.new-title h3');
        this.input = this.body.querySelector('input');
        // 将options复制到组件实例上
        _.mixin(this,options);
        this._renderUI();
        this._initEvent();
        return this;
    }
    //这里使用显示混入的方式,也可以使用原型对象关联的方式 Modal.prototype = Object.create({})
    _.mixin(Modal.prototype, {
        layout: _.htmlTranslate(template),
        // 添加节点
        appendTo: function(node) {
            node.appendChild(this.container);
        },
        // 显示弹窗
        show: function(content) {
            this.container.style.display = 'block';
        },
        // 隐藏弹窗
        hide: function() {
            this.container.style.display = 'none';
        },
        // 销毁弹窗
        destroy: function() {
            this.container.parentNode.removeChild(this.container);
        },
      
        _renderUI: function() {
            if(this.hasFlag === true) {
                // this.body.removeChild('hasInput')
                this.input.parentNode.removeChild(this.input);
                this.text && (this.bodyContent.innerText = this.text);
            }
          },
        _initEvent: function() {
            _.addEvent(this.container.querySelector('.confirm'), 'click', this.onConfirm.bind(this));
            _.addEvent(this.container.querySelector('.cancel'), 'click', this.onCancel.bind(this));

        },
        onConfirm: function() {
            this.emit('confirm');
            this.destroy();
        },
        onCancel: function() {
            this.emit('cancel');
            this.destroy();
        }
    })
     // 使用混入Mixin的方式使得Modal具有事件发射器功能
     _.mixin(Modal.prototype, _.emitter);
    //  暴露到全局
    window.Modal = Modal;
})(util)


//main.js
 new Modal()
        .on('confirm', function() {
                if(this.input.value.trim() != '') {
                    var index = '';
                    if(selectCG.className.indexOf('sub-category') != -1) {
                        index = '' + (data.category.push({name: this.input.value, number: 0, todos: [], subCategory: []}) - 1);
                    } else {
                        index = selectCG.index + '-' + (data.category[selectCG.index].subCategory.push({name: this.input.value, number: 0, todos:[]}) - 1);  
                    }
                }
                // 更新分类列表
                updateCGList(data.category, index);
                _.save(data);
            })
         .appendTo(document.body);

主要在构造函数function Modal(options) 声明属性赋值以及初始化工作,通过混入在Modal.prototype定义方法,然后调用new Modal时侯一次实现构造和初始化工作。然后通过链式调用需要的方法。

对象关联风格与行为委托设计模式

(function(_) {
    var template = 
    `<div class="overlay">
         <div class="box">
            <div class="box-title">
                <h3>消息提醒</h3>
                <div class="box-close icon-cross1"></div>
            </div>
            <div class="box-main">
                <div class="new-title">
                    <h3 class="nameValue">名称:</h3>
                    <input type="text">
                </div>
                <button class="btn2 confirm">确定</button>
                <button class="btn2 cancel">取消</button>
            </div>
        </div> 
    </div>`;
     
    var Modal = {
        init: function(options) {
            this.options = options || {}; 
            this.container = this.layout.cloneNode(true);
            
            this.body = this.container.querySelector('.new-title');
            this.bodyContent = this.container.querySelector('.new-title h3');
            this.input = this.body.querySelector('input');
            修改原型链使Modal对象的原型链上有_.emitter的方法
            Object.setPrototypeOf(Modal,_.emitter);
            this._renderUI();
            this._initEvent();
           
        },
        layout: _.htmlTranslate(template),
        // 添加节点
        appendTo: function(node) {
            node.appendChild(this.container);
        },
        // 显示弹窗
        show(content) {
            this.container.style.display = 'block';
        },
        // 隐藏弹窗
        hide() {
            this.container.style.display = 'none';
        },
        // 销毁弹窗
        destroy() {
            this.container.parentNode.removeChild(this.container);
        },
       
        _renderUI: function() {
            if(this.options.hasFlag === true) {
                // this.body.removeChild('hasInput')
                this.input.parentNode.removeChild(this.input);
                this.options.text && (this.bodyContent.innerText = this.options.text);
            } 
          },
        _initEvent: function() {
            _.addEvent(this.container.querySelector('.confirm'), 'click', this.onConfirm.bind(this));
            _.addEvent(this.container.querySelector('.cancel'), 'click', this.onCancel.bind(this));

        },
        onConfirm() {
            this.emit('confirm');
            this.destroy();
        },
        onCancel() {
            this.emit('cancel');
            this.destroy();
        }
        
    }
    //  暴露到全局
    window.Modal = Modal;
})(util)

对象关联这种风格只需要在组件上定义一个对象,不在需要prototype定义方法属性了。也不需要显示混入的复制方式,而是使用es6的新方法 Object.setPrototypeOf()修改[[prototype]]链达到同样的目的。但是在调用的时候实现构造实例化初始化的时候需要分两步(关联对象和初始化),而且它不能通过类与继承的方式.().().()这样直接链式调用方法,不过这样对初学者来说可以增加代码的可读性,也更好实现关注分离原则。

个人看法

之前第一次看你不知的js的时候作者对对象关联与行为委托的设计模式不断的赞赏,而不断对js的类与继承的模式进行吐槽。这可能作者觉得js应该使用自己的独有的语言风格而不是极力地模仿类的方式。个人觉得js有意让这两种模式都能平衡地发展,因为es6为了两种模式都添加了新的语法,如class, Object.setPrototypeOf()方法等。所以,我觉得两种模式看个人选择,没有好坏之分,重点是实现功能完成项目。

posted @ 2020-08-24 18:22  lqmrt  阅读(156)  评论(0编辑  收藏  举报