• 委托模式


    今天看书,了解到一个相较于类继承模式更好的一种编程思维:委托模式。

    委托模式的实现原理依托于原型链。一个对象委托于另一个对象,两者共同来完成一件事情。因为有原型链的存在,因此如果将一个对象委托于另一个对象,那么,在委托者的原型链中就可以找到对应的方法和属性。在js语言中,委托模式比继承模式更加轻松便捷,易于理解。

    举个例子,在新建组件的时候,如果使用类模式定义的话:

    // 父类
    function Widget(width,height) {
        this.width = width || 50;
        this.height = height || 50;
        this.$elem = null;
    }
    Widget.prototype.render = function($where){
        if (this.$elem) {
            this.$elem.css( {
                 this.width + "px",
                height: this.height + "px"
            } ).appendTo( $where );
         }
    };
    // 子类
    function Button(width,height,label) {
          // 调用“super”构造函数
          Widget.call( this, width, height );
          this.label = label || "Default";
          this.$elem = $( "<button>" ).text( this.label );
    }
    // 让Button“继承”Widget
    Button.prototype = Object.create( Widget.prototype );
    // 重写render(..)
    Button.prototype.render = function($where) {
        // “super”调用,因为this是根据函数调用时的环境决定值,this指向window,所以需要显示的绑定this对象
        Widget.prototype.render.call( this, $where );
        this.$elem.click( this.onClick.bind( this ) );
    };
    Button.prototype.onClick = function(evt) {
        console.log( "Button '" + this.label + "' clicked!" );
    };
    $( document ).ready( function(){
        var $body = $( document.body );
        var btn1 = new Button( 125, 30, "Hello" );
        var btn2 = new Button( 150, 40, "World" );
        btn1.render( $body ); 
        btn2.render( $body );
    } );

    这种方法的问题是因为js中没有类的概念,因此在模拟类的时候会导致this指向问题,同时可能还会有冗余constructor和prototype问题,而且代码看上去很繁琐。

    如果使用委托模式定义的话:

    var Widget = {
           init: function(width,height){
                  this.width = width || 50;
                  this.height = height || 50;
                  this.$elem = null;
           },
           insert: function($where){ 
                    if (this.$elem) {
                        this.$elem.css( {
                                this.width + "px",
                               height: this.height + "px"
                        } ).appendTo( $where );
                    }
            }
    };
    // 重点在下面这句:因为新建了一个Widget对象,并把它赋值给了Button,因此Button拥有了Widget里的属性,因为原型链将Widget和Button相联系,Button的原型链里包含了Widget。
    var Button = Object.create( Widget );
    Button.setup = function(width,height,label){
                   // 委托调用
                   this.init( width, height );
                   this.label = label || "Default";
                   this.$elem = $( "<button>" ).text( this.label );
    };
    Button.build = function($where) {
                   // 委托调用
                   this.insert( $where );
                   this.$elem.click( this.onClick.bind( this ) );
    };
    Button.onClick = function(evt) {
                 console.log( "Button '" + this.label + "' clicked!" );
    };
    $( document ).ready( function(){
    var $body = $( document.body );
        // 采用委托模式的新建方法:
        var btn1 = Object.create( Button );
    // 相当于初始化了btn1,类似于var btn1 = new Button(125, 30, “hello”);
        // 但这种方式的好处是不会产生多余的constructor和peototype问题
        btn1.setup( 125, 30, "Hello" );
        var btn2 = Object.create( Button );
        btn2.setup( 150, 40, "World" );
        btn1.build( $body );
        btn2.build( $body );
    } );

    代码清晰明了,同时没有多余的constructor问题,因为没有用new来声明变量,但他也会存在问题,就是如果需要迭代调用函数的话,就不要使用匿名函数,因为可能会找不到函数或者无法调用函数,最好使用具名函数定义:

    var Widget = {
           init: function init (n){
                  while(n <10){
                     return init(n++);
                  }
                 return n;
           }
    };
  • 相关阅读:
    微信小程序实战练习(仿五洲到家微信版)
    vue2.0项目 calendar.js(日历组件封装)
    基于thinkphp的后台管理系统模板快速搭建
    你不知道的javascript(上卷)读后感(二)
    你不知道的javascript(上卷)读后感(一)
    教你10分钟搭建酷炫的个人博客
    Webpack学习-工作原理(下)
    Webpack学习-工作原理(上)
    Css Secret 案例Demo全套
    基于excel导入数据到ms sql server
  • 原文地址:https://www.cnblogs.com/Candybunny/p/5484135.html
Copyright © 2020-2023  润新知