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
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
2
3
4
5
# 静态属性继承
for (var i in this) {
if (/*...*/) {
NewClass[i] = this[i]; // 复制父类静态属性到子类
}
}
1
2
3
4
5
2
3
4
5
# 混入处理(Mixin
)
if (props.includes) {
Util.extend.apply(null, [proto].concat(props.includes));
}
// 等价于将多个对象的属性合并到原型
1
2
3
4
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