openalyers6.x源码解读-1(世上无难事只要肯放弃)

第一步、下载源码

源码下载地址 https://github.com/openlayers/openlayers

第二步、查找入口文件

源码下载后执行npm i 安装好所有的依赖会看到如下界面:
openlayers主目录
openlayers的核心源码都存在于src/ol下面,在里面找到index.js

第三步、先强行解析一个方法

在index.js暴露的口子中先找个软柿子捏捏,找来找去找到了这个东西

export {getUid, VERSION} from './util.js';

getUid就是给每个openlayers对象设置id的

/**
 * 获取对象的唯一 ID。 这会改变对象,以便进一步调用
 * 与参数相同的对象返回相同的值。 生成唯一 ID
 * 作为严格递增的序列。 改编自 goog.getUid。
 * @param {Object} obj 要为其获取唯一 ID 的对象。
 * @return {string} 对象的唯一 ID。
 * @api
 */
export function getUid(obj) {
  return obj.ol_uid || (obj.ol_uid = String(++uidCounter_));
}

这里面设计两个我的知识盲区,一个是jsDoc,一个是String,@api大概是jsDoc的接口的标识,而String(num)第一次见,按以前的习惯我估计会使用

var convert = 123 + ""

或者

var a = 123 ; var convert = a.toString()

感慨:哎!还是别人的代码优雅,啥也不是

第三步、Object

据说openlayers中ol.Object是个非常核心的东西,所有的Map、Layer。。都继承与它,而它内部集成了好多继承的方法,这就先看看它
忽略那么多注释可以看到下面的逻辑

/**
 * @classdesc
 * 事件被 {@link module:ol/Object~BaseObject} 的实例触发.
 */
export class ObjectEvent extends Event {
}

class BaseObject extends Observable {
}

爬上山顶的时候总是想长舒一口气“终于到头了”,现实到了顶上后忍不住来一句“卧槽😂”
基础类继承了Observable,这个看起来像是监听的基础类的东西,期指一算,它还会再继承一些东西,算了睡觉了,改天再说(世上无难事,只要肯放弃)
睡了一觉,状态还好,继续自虐,梳理下下Object的继承关系可以看到这条线

Object extends Observable  extends EventTarget extends Disposable 

大概也就是:基础类->监听类->目标类->可注销类
先记住这个线,至于为啥这么继承这个后续再说(如果想起来的hua)

  1. Disposable
/**
 * @module ol/Disposable
 */

/**
 * @classdesc
 * 需要自行清理的对象。
 */
class Disposable {
  constructor() {
    /**
     * 该对象是否已被释放。
     * @type {boolean}
     * @protected
     */
    this.disposed = false;
  }

  /**
   * 清理。
   */
  dispose() {
    if (!this.disposed) {
      this.disposed = true;
      this.disposeInternal();
    }
  }

  /**
   * 内部扩展。
   * @protected
   */
  disposeInternal() {}
}

export default Disposable;

很简单,不过感觉这个是个被放弃的方法,在其他gis前端框架中经常遇到,现在很少使用了,可能是每个类的释放方法都不一样吧
2. Target

/**
 * @module ol/events/Target
 */
class Target extends Disposable {
  /**
   * @param {*} [opt_target] 默认目标事件 for dispatched events.
   */
  constructor(opt_target) {
  }

  /**
   * @param {string} type Type.
   * @param {import("../events.js").Listener} listener 监听。
   */
  addEventListener(type, listener) {
  }

  /**
   * 触发事件并执行所有的监听器,事件参数可以是字符串也可以是带有type的Object
   *
   * @param {import("./Event.js").default|string} event 事件.
   * @return {boolean|undefined} `false` 如果有阻止冒泡或者所有监听器都返回false则整体返回false
   * @api
   */
  dispatchEvent(event) {
  }

  /**
   * Clean up.
   */
  disposeInternal() {
  }

  /**
   * 获取指定事件类型的监听器。 in the order that they will be called in.
   *
   * @param {string} type Type.
   * @return {Array<import("../events.js").Listener>|undefined} 监听器.
   */
  getListeners(type) {
  }

  /**
   * @param {string} [opt_type] Type. 如果不传参数则返回是否有listeners
   * @return {boolean} 是否含有监听器。
   */
  hasListener(opt_type) {
  }

  /**
   * @param {string} type Type.
   * @param {import("../events.js").Listener} listener Listener.
   */
  removeEventListener(type, listener) {
  }
}

export default Target;

Target中其实就是些事件监听,一些Event的精简化实现,如果不理解可以查下事件的委托,猫叫–>老鼠跑–>主人被吵醒 。
就代码来看跟所继承的dispose没有什么太大关联,只能再继续往下探索了
在hasListener 中看到一个方法

  hasListener(opt_type) {
    if (!this.listeners_) {
      return false;
    }
    return opt_type
      ? opt_type in this.listeners_
      : Object.keys(this.listeners_).length > 0;
  }

有点感触的就是 in 这个东西,说实话以前用的最对的就是for in 在对象中遍历,如果判断对象中是否有某个属性的话第一反应是if(object[target]),但不太严谨,万一存在但是值是false呢 ,于是乎就又想到了

Object.hasOwnProperty.call(this.listeners_,opt_type )

in 和 hasOwnProperty 的区别在哪呢 ,查了一下hasOwnProperty只能查看实例化,也就是new 之后的属性,挂载在原型上的东西是看不了的,而in 即能查看实例对象,也能查看原型上的属性,这么分析的话in似乎更精确一点,而且in的单词拼写量更少,何乐而不为呢 ,不过this.listeners 在addEventListener方法中是通过

const listeners = this.listeners_ || (this.listeners_ = {});

赋值的,为了性能考虑建议使用

Object.create(null)

使其少一些{}从原生Object继承来的原型属性,减少了内存,但从一个Object考虑的话肯定差别不大,但整个项目,而且大多类都继承的话性能影响的话肯定不容小觑(从尤雨溪的vue中学来的)
3. Observable

class Observable extends EventTarget {
  constructor() {
    super();

    /***
     * @type {OnSignature<EventTypes, import("./events/Event.js").default, OnReturn>}
     */
    this.on = this.onInternal;

    /***
     * @type {OnSignature<EventTypes, import("./events/Event.js").default, OnReturn>}
     */
    this.once = this.onceInternal;

    /***
     * @type {OnSignature<EventTypes, import("./events/Event.js").default, void>}
     */
    this.un = this.unInternal;

    /**
     * @private
     * @type {number}
     */
    this.revision_ = 0;
  }

  /**
   * Increases the revision counter and dispatches a 'change' event.
   * @api
   */
  changed() {
    ++this.revision_;
    this.dispatchEvent(EventType.CHANGE);
  }

  /**
   * Get the version number for this object.  Each time the object is modified,
   * its version number will be incremented.
   * @return {number} Revision.
   * @api
   */
  getRevision() {
    return this.revision_;
  }

  /**
   * @param {string|Array<string>} type Type.
   * @param {function(?): ?} listener Listener.
   * @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Event key.
   * @protected
   */
  onInternal(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);
    }
  }

  /**
   * @param {string|Array<string>} type Type.
   * @param {function(?): ?} listener Listener.
   * @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Event key.
   * @protected
   */
  onceInternal(type, listener) {
    let key;
    if (Array.isArray(type)) {
      const len = type.length;
      key = new Array(len);
      for (let i = 0; i < len; ++i) {
        key[i] = listenOnce(this, type[i], listener);
      }
    } else {
      key = listenOnce(this, /** @type {string} */ (type), listener);
    }
    /** @type {Object} */ (listener).ol_key = key;
    return key;
  }

  /**
   * Unlisten for a certain type of event.
   * @param {string|Array<string>} type Type.
   * @param {function(?): ?} listener Listener.
   * @protected
   */
  unInternal(type, listener) {
    const key = /** @type {Object} */ (listener).ol_key;
    if (key) {
      unByKey(key);
    } else if (Array.isArray(type)) {
      for (let i = 0, ii = type.length; i < ii; ++i) {
        this.removeEventListener(type[i], listener);
      }
    } else {
      this.removeEventListener(type, listener);
    }
  }
}

有了前面两段代码的基础这个就好理解多了,如果说Target是事件,Observable就是添加删除事件的的快捷方式/语法糖,加了on 和 un 的方法,类似前端的document.on(“click”,function(){})
document就是Target,给Target添加了 click 的一个事件
5. Object
这个看过代码之后感觉没什么东西,继承自Oberiveable,也就是在他之上加了些设置属性,以及更新的方法。

好了,到这对Object的解析就差不多了 ,本来是想怒撸前端gis的结果对前端代码的优雅性有了更深的感悟,也算是看别人代码的一点好处吧。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值