Jinuss's blog Jinuss's blog
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

前端可视化
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 框架

  • core模块

    • Leaflet自定义基类Class
      • 概述
      • 源码分析正文
        • 源码如下
        • 整体设计思想
        • 核心方法解析
        • 原型链结构示例
        • 关键技术点
        • 构造函数初始化流程
        • 静态属性继承
        • 混入处理(Mixin)
        • 设计理念总结
        • 与标准 JS 类的对比
      • 总结
    • 事件Event实现原理
    • Util工具方法
    • 浏览器判断方法Browser
  • dom模块

  • control

  • geometry

  • geo

  • layer

  • Map

  • 《Leaflet源码》笔记
  • core模块
东流
2025-03-11
目录

Leaflet自定义基类Class

# 概述

Leaflet 的设计哲学,即轻量级和可扩展性。在 core 模块,Leaflet 定义了一个Class类,用于实现类继承和扩展,提供一套面向对象的继承机制。

# 源码分析正文

# 源码如下

export function Class() {}

Class.extend = function (props) {
  var NewClass = function () {
    Util.setOptions(this); //设置 options
    if (this.initialize) {
      this.initialize.apply(this, arguments); //调用子类初始化方法
    }
    this.callInitHooks(); //触发初始化钩子
  };

  var parentProto = (NewClass.__super__ = this.prototype);
  var proto = Util.create(parentProto); //等价于Object.create
  proto.constructor = NewClass;

  NewClass.prototype = proto;

  for (var i in this) {
    if (
      Object.prototype.hasOwnProperty.call(this, i) &&
      i !== "prototype" &&
      i !== "__super__"
    ) {
      NewClass[i] = this[i];
    }
  }

  if (props.statics) {
    Util.extend(NewClass, props.statics);
  }

  if (props.includes) {
    checkDeprecatedMixinEvents(props.includes);
    Util.extend.apply(null, [proto].concat(props.includes));
  }

  Util.extend(proto, props);

  delete proto.statics;
  delete proto.includes;

  if (proto.options) {
    proto.options = parentProto.options ? Util.create(parentProto.options) : {};
    Util.extend(proto.options, props.options);
  }

  proto._initHooks = [];
  proto.callInitHooks = function () {
    if (this._initHooksCalled) {
      return;
    }

    if (parentProto.callInitHooks) {
      parentProto.callInitHooks.call(this);
    }

    this._initHooksCalled = true;

    for (var i = 0, len = proto._initHooks.length; i < len; i++) {
      proto._initHooks[i].call(this);
    }
  };

  return NewClass;
};

Class.include = function (props) {
  var parentOptions = this.prototype.options;
  Util.extend(this.prototype, props);
  if (props.options) {
    this.prototype.options = parentOptions;
    this.mergeOptions(props.options);
  }

  return this;
};

Class.mergeOptions = function (props) {
  Util.extend(this.prototype.options, props);
  return this;
};

Class.addInitHook = function (fn) {
  var args = Array.prototype.slice.call(arguments, 1);

  var init =
    typeof fn === "function"
      ? fn
      : function () {
          this[fn].apply(this, args);
        };

  this.prototype._initHooks = this.prototype._initHooks || [];
  this.prototype._initHooks.push(init);
  return this;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

# 整体设计思想

Leaflet 的类系统基于 ​ 原型链继承 + ​Mixin 模式,允许:

  • 通过 extend() 创建子类

  • 通过 include() 混入额外方法

  • 通过 mergeOptions() 合并配置

  • 通过 addInitHook() 添加初始化钩子

# 核心方法解析

  • Class.extend(props)

    • 作用:创建当前类的子类

    • 原理:

      • 创建一个新的类 NewClass,继承自当前类
      • 复制当前类的原型到新类的原型上
      • 复制当前类的静态方法到新类上
      • 复制 props 中的方法到新类的原型上
      • 复制 props 中的静态方法到新类上
      • 复制 props 中的 options 到新类的原型上
      • 返回新类
  • Class.include(props)

    • 作用:在当前类的原型上混入额外方法或属性

    • 原理:

      • 使用Util.extend复制 props 中的方法到当前类的原型上
      • 复制 props 中的 options 到当前类的原型上
      • 返回当前类
  • Class.mergeOptions(props)

    • 作用:合并配置到当前类的原型上
    • 原理:
      • 使用Util.extend复制 props 中的 options 到当前类的原型上
      • 常用于继承时保留父类配置
  • Class.addInitHook(fn, ...args)

    • 作用:添加初始化时执行的钩子函数
    • 原理
      • 将钩子函数存入_initHooks数组
      • 实例化时通过callInitHooks()按顺序执行

# 原型链结构示例

假设有继承链 Parent → Child → Grandchild,其原型链结构为:

Grandchild.prototype → Child.prototype → Parent.prototype → Object.prototype 通过 NewClass.__super__ 可访问父类原型

# 关键技术点

# 构造函数初始化流程

var obj = new MyClass();
// 执行顺序:
1. Util.setOptions(this) // 初始化配置
2. initialize()          // 自定义初始化逻辑
3. callInitHooks()       // 执行所有注册的钩子函数
1
2
3
4
5

# 静态属性继承

for (var i in this) {
  if (/*...*/) {
    NewClass[i] = this[i]; // 复制父类静态属性到子类
  }
}
1
2
3
4
5

# 混入处理(Mixin)

if (props.includes) {
  Util.extend.apply(null, [proto].concat(props.includes));
}
// 等价于将多个对象的属性合并到原型
1
2
3
4

# 设计理念总结

特性 实现方式 优势
​ 继承 原型链 (Object.create) 保留父类方法
​ 配置合并 mergeOptions 可覆盖默认配置
​ 代码复用 include() 混入 模块化扩展功能
​ 生命周期管理 addInitHook 钩子 解耦初始化逻辑

# 与标准 JS 类的对比

功能 Leaflet Class ES6 Class
继承 extend() extends
混入 include() 无原生支持,需用 Mixin 模式
静态属性继承 自动复制 需手动 super 调用
初始化钩子 addInitHook() 构造函数内直接处理

# 总结

这段代码是 Leaflet 轻量级架构的核心,使得地图组件可以灵活扩展,同时保持代码可维护性。

编辑 (opens new window)
上次更新: 2025/03/17, 01:35:24
Leaflet基础介绍
事件Event实现原理

← Leaflet基础介绍 事件Event实现原理→

最近更新
01
GeoJSON
05-08
02
Circle
04-15
03
CircleMarker
04-15
更多文章>
Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式