Openlayers 源码分析-BaseObject

要分析框架的源码,首先需要从基类开发,在OpenlayersBaseObject可以说是很多类的基类,比如MapViewLayerOverlay等这些类,都 是继承于BaseObject,就先从BaseObject这个类来开始看。BaseObject并不是最顶端的基础,也是继承于其它的类,继承关系如下所示:

Disposable》Target》Observable》BaseObject

下面就这几个类来进行分析。

1.Disposable

Disposable可以说是所有相关类的老祖宗,该类的代码很简洁,提供的方法也就两个。分别是dispose()disposeInternal()。该类的主要作用是清除对象和事件等信息,一般在子类通过重写disposeInternal()方法处理清空的逻辑,调用dispose()来执行清除的操作。

2.Target

Target是一个目标对象,主要用于管理相关的事件,添加事件,移除事件、派发事件等操作都是使用该类来处理。

2.1构造函数

Target 的构造函数主要是用于实例化pendingRemovals_dispatching_dispatching_等属性,定义属性的时候在属性名后面加了下划线表示为私有变量。

constructor(opt_target) {

    super();

    /**
     * @private
     * @type {*}
     * 参数信息
     */
    this.eventTarget_ = opt_target;

    /**
     * @private
     * @type {!Object<string, number>}
     * 待删除的事件
     */
    this.pendingRemovals_ = {};

    /**
     * @private
     * @type {!Object<string, number>}
     * 派发中的事件
     */
    this.dispatching_ = {};

    /**
     * @private
     * @type {!Object<string, Array<import("../events.js").ListenerFunction>>}
     * 所有事件
     */
    this.listeners_ = {};

  }

2.2添加事件

添加事件的逻辑为先根据typelisteners_中获取,如果没被添加过,就先初始化数组,然后再进行添加。

addEventListener(type, listener) {
    if (!type || !listener) {//type和listener不能为空
      return;
    }
    let listeners = this.listeners_[type];
    if (!listeners) {//为空时初始化数组
      listeners = [];
      this.listeners_[type] = listeners;
    }
    if (listeners.indexOf(listener) === -1) {
      listeners.push(listener);
    }
  }

2.3事件派发

使用dispatchEvent可以对事件进行派发,派发完成后,执行removeEventListener进行删除。

删除事件

该方法主要是通过typelistenerlisteners_中对应的事件删除。

removeEventListener(type, listener) {
    const listeners = this.listeners_[type];
    if (listeners) {
      const index = listeners.indexOf(listener);
      if (index !== -1) {
        if (type in this.pendingRemovals_) {
          // make listener a no-op, and remove later in #dispatchEvent()
          listeners[index] = VOID;
          ++this.pendingRemovals_[type];
        } else {
          listeners.splice(index, 1);
          if (listeners.length === 0) {
            delete this.listeners_[type];
          }
        }
      }
    }
  }
dispatchEvent(event) {
    //判断event类型
    const evt = typeof event === 'string' ? new Event(event) : event;
    const type = evt.type;
    if (!evt.target) {//找到事件的上档对象
      evt.target = this.eventTarget_ || this;
    }
    const listeners = this.listeners_[type];
    let propagate;
    if (listeners) {
      if (!(type in this.dispatching_)) {//判断有没有正在派发的
        this.dispatching_[type] = 0;
        this.pendingRemovals_[type] = 0;
      }
      ++this.dispatching_[type];//开始派发事件
      for (let i = 0, ii = listeners.length; i < ii; ++i) {
        if (listeners[i].call(this, evt) === false || evt.propagationStopped) {
          propagate = false;
          break;
        }
      }
      --this.dispatching_[type];//事件派发结束
      if (this.dispatching_[type] === 0) {
        let pendingRemovals = this.pendingRemovals_[type];
        delete this.pendingRemovals_[type];
        while (pendingRemovals--) {//移除事件
          this.removeEventListener(type, VOID);
        }
        delete this.dispatching_[type];
      }
      return propagate;
    }
  }

3.Observable

Observable是一个观察者对象,这里主要运行了设计模式中的观察者模式,用于订阅和发布事件,该类主要包括ononceun等方法。

3.1on

用于添加事件,主要是使用listen方法来调用Target类的addEventListener来添加。

on(type, listener) {
    if (Array.isArray(type)) {//数组,多个事件使用的是同一个函数回调
      const len = type.length;
      const keys = new Array(len);
      for (let i = 0; i < len; ++i) {//遍历数组进行添加
        keys[i] = listen(this, type[i], listener);
      }
      return keys;
    } else {
      return listen(this, /** @type {string} */ (type), listener);
    }
  }

3.2once

同样的事件类型不能重复添加。

 once(type, listener) {
    if (Array.isArray(type)) {
      const len = type.length;
      const keys = new Array(len);
      for (let i = 0; i < len; ++i) {
        keys[i] = listenOnce(this, type[i], listener);
      }
      return keys;
    } else {
      return listenOnce(this, /** @type {string} */ (type), listener);
    }
  }

3.3 un

用于删除事件,主要调用Target类的removeEventListener来移除事件。

un(type, listener) {
    if (Array.isArray(type)) {
      for (let i = 0, ii = type.length; i < ii; ++i) {
        this.removeEventListener(type[i], listener);
      }
    } else {
      this.removeEventListener(type, listener);
    }
  }

4.BaseObject

BaseObject主要用于往对象中动态添加属性和属性值,在初使化的时候,可以通过构造函数来传递默认添加的对象,然后调用setPropertiesvalues_赋值,如下所示:

 constructor(opt_values) {
    super();
    getUid(this);
    this.values_ = {};

    if (opt_values !== undefined) {//设置属性
      this.setProperties(opt_values);
    }
  }

setProperties(values, opt_silent) {
    for (const key in values) {
      this.set(key, values[key], opt_silent);
    }
  }

在调用set方法的时候,其中一个流程用到了notify方法,使用该方法可以通知属性的变化,如下所示:

set(key, value, opt_silent) {
    if (opt_silent) {
      this.values_[key] = value;
    } else {
      const oldValue = this.values_[key];
      this.values_[key] = value;
      if (oldValue !== value) {
        this.notify(key, oldValue);
      }
    }
  }

notify(key, oldValue) {
    let eventType;
    eventType = getChangeEventType(key);
    //派发‘change:属性名’的事件
    this.dispatchEvent(new ObjectEvent(eventType, key, oldValue));
    eventType = ObjectEventType.PROPERTYCHANGE;
    //派发PROPERTYCHANGE事件
    this.dispatchEvent(new ObjectEvent(eventType, key, oldValue));
  }

getProperties() {
    return assign({}, this.values_);//复制一个新的对象返回
  }

BaseObject先分析到此了,代码一路看下来,不得不说这个框架的代码写的很好,很简洁,很有参考价值,设计模式也用的很到位,值得慢慢品味。真香!
个人博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容

  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 9,196评论 0 3
  • 面向对象的三大特性:封装、继承、多态 OC内存管理 _strong 引用计数器来控制对象的生命周期。 _weak...
    运气不够技术凑阅读 1,098评论 0 10
  • 面向对象主要针对面向过程。 面向过程的基本单元是函数。 什么是对象:EVERYTHING IS OBJECT(万物...
    sinpi阅读 1,054评论 0 4
  • 1.import static是Java 5增加的功能,就是将Import类中的静态方法,可以作为本类的静态方法来...
    XLsn0w阅读 1,222评论 0 2
  • http://liuxing.info/2017/06/30/Spring%20AMQP%E4%B8%AD%E6%...
    sherlock_6981阅读 15,910评论 2 11