• 观察者模式(2)--自定义事件


    [附加题] 请实现下面的自定义事件 Event 对象的接口,功能见注释(测试1)
    该 Event 对象的接口需要能被其他对象拓展复用(测试2)
    // 测试1
    Event.on('test', function (result) {
        console.log(result);
    });
    Event.on('test', function () {
        console.log('test');
    });
    Event.emit('test', 'hello world'); // 输出 'hello world' 和 'test'
    // 测试2
    var person1 = {};
    var person2 = {};
    Object.assign(person1, Event);
    Object.assign(person2, Event);
    person1.on('call1', function () {
        console.log('person1');
    });
    person2.on('call2', function () {
        console.log('person2');
    });
    person1.emit('call1'); // 输出 'person1'
    person1.emit('call2'); // 没有输出
    person2.emit('call1'); // 没有输出
    person2.emit('call2'); // 输出 'person2'<br>var Event = {
        // 通过on接口监听事件eventName
        // 如果事件eventName被触发,则执行callback回调函数
        on: function (eventName, callback) {
            //你的代码
        },
        // 触发事件 eventName
        emit: function (eventName) {
            //你的代码
        }
    };

    这是一道笔试题,考察的就是观察者模式,包括事件的定义和执行。这里看一下用JS原型写的观察者模式基本试例。

    function Observer(){
      this.handlers={};   
    }
    Observer.prototype={
      constructor:Observer,
      addHandler:function(type,handler){
        if(!this.handlers[type]){
          this.handlers[type]=[];
        }
        this.handlers[type].push(handler);
      },
      emit:function(event){
        if(!event.target){
          event.target=this;
        }
        if(this.handlers[event] instanceof Array){
          var handlers=this.handlers[event];
          for(var i=0;i<handlers.length;i++){
            handlers[i]();    
          }
        }
      },
      removeHandlers:function(type,handler){
        if(this.handlers[type] instanceof Array){
          var handlers=this.handlers[type];
          for(var i=0;i<handlers.length;i++){
            if(handlers[i]===handler){   
              break;
            }
          }
          handlers.splice(i,1);
        }
      }  
    }

    题目中的测试一,在事件触发时(emit),如果有参数,需要接收参数,如果没有参数,则直接忽略传参。

    我们可以这样写:

    var Event={
      on:function(event,callback){
        if(!this.handlers){
          this.handlers={};
        }
        if(!this.handlers[event]){
          this.handlers[type]=[];
        }
        this.handlers[type].push(event);

      },
      emit:funciton(event){
        var handlers=this.handlers[event];
        if(handlers){
          for(var i=0;i<handlers.length;i++){
            handlers[i](arguments[1]); //执行时的第二个参数,为传函数的参数
          }
        }
      }

    }

      测试二的意思简单来说就是,两个不同的对象的自定义事件之间相互独立。

      在题目中提到了一个ES6的函数:Object.assign(target,source);作用是将源对象(source)中的所有可枚举属性复制到目标对象(target)中。在这个题中的意思就是,将Event中的可枚举对象放到person中。

      由于复制的是一个对象,而对象为引用类型,所以用Object.assign(target,source) 操作之后,复制的其实只是对象的引用。因此,person1和person2之间不独立。这显然不符合要求。那我们应该怎么做呢?既然Object.assign(target,source);复制的是可枚举的属性,那我们只要在定义handlers,将其定义为不可枚举属性即可,然后在person调用on方法时分别产生各自的handlers对象。

    那新的代码应该这样:

    var Event={
      on:function(event,callback){
        if(!this.handlers){
          Object.defineProperty(this,'handlers',{
                  value:{},
             enumberable:false,   //不可枚举
             configurable:true,
             writable:true
              });
        }
        if(!this.handlers[event]){
          this.handlers[type]=[];
        }
        this.handlers[type].push(event);
      },
      emit:funciton(event){
        var handlers=this.handlers[event];
        if(handlers){
          for(var i=0;i<handlers.length;i++){
            handlers[i](arguments[1]);   //执行时的第二个参数,为传函数的参数
          }
        }
      }
    }

    这里用到了Object.defineProperty(),表示将属性添加到对象,或修改现有属性的特性。

    先看一个简单的例子:

      var a= {}

      Object.defineProperty(a,"b",{ value:123 })

      console.log(a.b);//123     它接受三个参数,而且都是必填的。。

    传入参数

    第一个参数:目标对象

    第二个参数:需要定义的属性或方法的名字。

    第三个参数:目标属性所拥有的特性。(descriptor)。

    descriptor

    有以下取值:

    value:属性的值。

    writable:如果为false,属性的值就不能被重写,只能为只读了,默认值为:true。

    configurable:总开关,一旦为false,就不能再设置他的(value,writable,configurable)

    enumberable:是否能在for...in循环中遍历出来或在Object.keys中列举出来,默认值为true。

    这里我们不想属性可枚举,只需要在定义的时候将enumberable设置为false。

     

  • 相关阅读:
    洛谷 P2915 [USACO08NOV]奶牛混合起来Mixed Up Cows 题解
    洛谷 P2687 [USACO4.3]逢低吸纳Buy Low, Buy Lower/ACWing 314 低买 题解
    7、Python异常
    必须要调整心态,积极起来,不能再偷懒
    5、Python函数
    10、Python数据库支持
    8、Python方法、属性、迭代器
    9、Python模块和标准库
    6、Python抽象的类
    UDP Linux编程(客户端&服务器端)
  • 原文地址:https://www.cnblogs.com/telnetzhang/p/5817526.html
Copyright © 2020-2023  润新知