openalyers6.x源码解读-1(世上无难事只要肯放弃)
第一步、下载源码
源码下载地址 https://github.com/openlayers/openlayers
第二步、查找入口文件
源码下载后执行npm i 安装好所有的依赖会看到如下界面:
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)
- 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的结果对前端代码的优雅性有了更深的感悟,也算是看别人代码的一点好处吧。