jQuery的入口函数, 也就是平时使用的$(xxx)诸如此类.

一、更新


[2019-4-21]

Changed

  • 文章格式调整

二、简单工厂模式


开始之前, 先回顾一下设计模式中所谓的简单工厂模式:

2.1 是什么?

PS: 根据不同的参数, 返回不同类的实例

简单来说, 就是:

  • 创建并对外暴露一个普通函数, 由于内部机制, 姑且就叫它工厂函数
  • 接受一个目标实例化类型的参数
  • 函数内部进行实例化(new)操作

2.2 为什么?

那么大致了解了简单工厂的工作流程, 现在我们做个简单的thinking:

  1. 为什么会出现这种设计模式?
  2. 它解决了什么痛点?

俗话说的好——事出必有因, 对于上述两个思考, 我觉得可以由以下两个方面概括:

  • 将对象的创建和使用解耦
    • 比如在开发中或多或少会用到插件, 那么实例化插件的过程中, 我们可能 会无意中丢失了new操作符, 导致后续报错, 这对于开发者是绝不能容忍的~, 而简单工厂解决了这个问题, 它将实例化的操作隐藏在了内部, 用户只需要知道自己想要什么, 而工厂则去做什么.
  • 降低代码重复
    • 假设对象的创建需要经历很多很多的步骤, 这对于有多个对象创建需求的用户来说就很蛋疼了, 这时候使用工厂模式就能免去冗余的操作, 增强用户体验

2.3 怎么做?

PS: 网上也有很多关于工厂模式的例子, 本人之前的项目也使用了该模式, 在这里还是不厌其烦的加上, 一方面为了作为参照, 另一方面也是对该设计模式的巩固.

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
class TypeA {
constructor(
private name: string,
) {}
}

class TypeB {
constructor(
private name: string,
) {}
}

function TypeFactory(
type: string,
options: {
[key: string]: any,
},
): TypeA | TypeB {
switch(type) {
case 'A': {
return new TypeA(options);
}
case 'B': {
return new TypeB(options);
}
default: {
throw new Error('Parameter `type` must be provided.');
}
}
}

三、jQuery工厂


通过上面的简单工厂模式的回顾, 我们了解了该种设计模式的出现到底有啥用. 那么回过头来, jQuery的源码中:

1
2
3
var jQuery = function(selector, context) {
return new jQuery.fn.init(selector, context);
}

可以看到, jQuery的入口函数与简单工厂的实例代码类似, 名为jQuery的函数接收两个参数:

  • selector
    • 选择器
  • context
    • 范围限制

在内部进行了实例化操作, 并且jQuery原型上的init方法才是真正的构造函数. 那么这里可能就会有疑问了:

Q: 为什么不直接暴露出jQuery.fn.init?

我们举例来分析:

1
2
3
4
5
6
7
8
9
/**
* 普通用法
*/
$(xxx).addClass(xxx).removeClass(xxx);

/**
* 直接暴露`jQuery.fn.init()`
*/
new jQuery.fn.init(xxx).addClass(xxx).removeClass(xxx);

可以看到, 一个简单的工厂函数, 为我们省去了不必要的操作.

那么至于为什么实例化一个原型上的方法呢? 我想, 这可能是作者的个人想法吧, 毕竟一千个人就有一千个哈姆雷特, 可能我自己在构建的时候会使用任何其他不同名的类, 取其精华, 去其糟粕, 阅读源码的过程不正是为了如此吗?

四、总结


本篇分析了jQuery工厂的创建流程, 以及为什么要设计如此这般, 下一篇文章会着重分析jQuery构造函数机制

五、示例代码


重构后的tsjs版本代码放置在了Gayhub