三种JavaScript类的实现方法(es5和es6)

前言:以toast组件为例子,通过三种方法实现toast类,希望对组件化开发的同学能有启发,学习代码组织的方式;对于组件化代码的开发大有裨益;

1.通过构造函数+原型实现类

1.1代码实现

   //构造函数,默认大写开头
    function Toast(option){
        this.prompt = '';    //toast中的内容
        this.elem = null;    //定义元素dom结构
        this.init(option);  //构造函数的入口;
    }
    Toast.prototype = {
        // 构造器
        constructor:Toast, //必须重新定义原型指向
        // 初始化方法
        init: function(option){
            this.prompt = option.prompt || '';
            this.render();
            this.bindEvent();
            return this;   //链式操作的核心,就可以在
        },
        // 显示
        show: function(time){
            var that=this;
            this.changeStyle(this.elem, 'display', 'block');
            setTimeout(function(){
                that.hide();
            },time);
        },
        // 隐藏
        hide: function(){
            this.changeStyle(this.elem, 'display', 'none');
        },
        // 画出dom
        render: function(){
            var html = '';
            this.elem = document.createElement('div');
            this.changeStyle(this.elem, 'display', 'none');
            html += 'x'
            html += '

'+ this.prompt +'

'; this.elem.innerHTML = html; return document.body.appendChild(this.elem); }, // 绑定事件 bindEvent: function(){ var self = this; this.addEvent(this.elem, 'click', function(e){ if(e.target.className.indexOf('J-close') != -1){ console.log('close Toast!'); self.hide(); } }); }, // 添加事件方法 addEvent: function(node, name, fn){ var self = this; node.addEventListener(name,function(){ fn.apply(self,Array.prototype.slice.call(arguments)); },false); }, // 改变样式 changeStyle: function(node, key, value){ node.style[key] = value; } }; var T=new Toast({prompt:'I\'m Toast!'}).show(2000); //链式操作

这里的优化,是把原型指向一个新的空对象{}。 带来的好处,就是可以用{key:value}的方式写原型上的方法和变量。 但是,这种方式会改变原型上构造器prototype.constructor的指向。 如果不重新显式声明constructor的指向,Toast.constructor.prototype.constructor的会隐式被指向Object。而正确的指向,应该是Toast。 虽然通过new实例化没有出现异常,但是在类继承方面,constructor的指向异常,会产生不正确的继承判断结果。这是我们不希望看到的。 所以,需要修正constructor

1.2.实例化与new操作符

类的实例化,一个强制要求的行为,就是需要使用new操作符。如果不使用new操作符,那么构造器内的this指向,将不是当前的实例化对象。 优化的方式,就是使用instanceof做一层防护。

function Toast(option){
  if(!(this instanceof Toast)){
    return new Toast(option);
  }

  //这里或者抛出一个错误的信息也可以
  if(!(this instanceof Toast)){
    throw new Error('Toast instantiation error');
  }

  this.prompt = '';
  this.elem = null;
  this.init(option);
}

1.3构造器方法/变量和原型中的方法变量之间的区别

原型上的方法和变量,是该类所有实例化对象共享的。也就是说,只有一份。 而构造器内的代码块,则是每个实例化对象单独占有。不管是否用this.**方式,还是私有变量的方式,都是独占的。 所以,在写一个类的时候,需要考虑该新增属性是共享的,还是独占的。以此,决定在构造器还是原型上进行声明。

2.构造函数+内部函数+对象字面量对外暴露

2.1代码实现

    function Toast(){
        // 已点歌曲
        function  init(option){
            this.prompt = option.prompt || '';
            render();
            bindEvent();
        }
        function show(time){
            changeStyle(this.elem, 'display', 'block');
            setTimeout(function(){
                hide();
            },time);
        }
       function  hide(){
           changeStyle(this.elem, 'display', 'none');
       }
       function  render(){
            var html = '';
            this.elem = document.createElement('div');
            changeStyle(this.elem, 'display', 'none');
            html += 'x'
            html += '

'+ this.prompt +'

'; this.elem.innerHTML = html; return document.body.appendChild(this.elem); } //绑定点击事件 function bindEvent(){ var self = this; addEvent(this.elem,'click',function(e){ if(e.target.className.indexOf('J-close') != -1){ self.hide(); }else{ alert("绑定的点击事件生效了"); } }); } // 添加绑定多种事件的方法 function addEvent(node,name,fn){ var self = this; node.addEventListener(name,function(){ fn.apply(self,Array.prototype.slice.call(arguments)); },false); } // 改变样式 function changeStyle(node,key,value){ node.style[key]=value; } /** * @date: 2018-07-24 * @Desc: 将上述方法综合起来使用,这些方法仅仅在构造函数内部进行使用,对外仅仅暴露开启和关闭方法即可 */ var service = { start: function(config){ init(config); //构造函数的入口; show(20000); }, stop: function(){ hide(); } }; return service; //将该组件的接口暴露出去 } var T= new Toast(); T.start({prompt:'I\'m Toast!',elem:document.getElementById("test")}); //先创建一个测试元素

2.2分析

在平时开发页面的过程中对于某一块的功能进行内部的封装,有点是代码组织简洁,需要提前规划好对外暴露的接口;

3.使用es6中的class来创建

3.1代码实现

  class Toast{
        // 已点歌曲
       init(option){
            this.prompt = option.prompt || '';
            render();
            bindEvent();
            show(2000);
        }
      show(time){
            changeStyle(this.elem, 'display', 'block');
            setTimeout(function(){
                hide();
            },time);
        }
       hide(){
            changeStyle(this.elem, 'display','none');
        }
       render(config){
            var html = '';
            this.elem = document.createElement('div');
            this.changeStyle(this.elem, 'display', 'block');
            html += 'x'
            html += '

'+ config.prompt +'

'; this.elem.innerHTML = html; return document.body.appendChild(this.elem); } //绑定点击事件 bindEvent(){ var self = this; this.addEvent(this.elem,'click',function(e){ if(e.target.className.indexOf('J-close') != -1){ self.hide(); }else{ alert("绑定的点击事件生效了"); } }); } // 添加绑定多种事件的方法 addEvent(node,name,fn){ var self = this; node.addEventListener(name,function(){ fn.apply(self,Array.prototype.slice.call(arguments)); },false); } // 改变样式 changeStyle(node,key,value){ node.style[key]=value; } } var T= new Toast(); T.render({prompt:'I\'m Toast!',elem:document.getElementById("test")}); //先创建一个测试元素 T.bindEvent();

3.2代码分析

class类实现可以通过extends对类进行方法继承;

 

 

 

 

 

 

 

你可能感兴趣的:(小知识点汇总)