从零开始,DIY一个jQuery(2)

在上篇文章我们简单实现了一个 jQuery 的基础结构,不过为了顺应潮流,这次咱把它改为模块化的写法,此举得以有效提升项目的可维护性,因此在后续也将以模块化形式进行持续开发。

模块化开发和编译需要用上 ES6 和 rollup,具体原因和使用方法请参照我之前的《冗余代码都走开——前端模块打包利器 Rollup.js 入门》一文。

本期代码均挂在我的github上,有需要的童鞋自行下载。

1. 基本配置

为了让 rollup 得以静态解析模块,从而减少可能存在的冗余代码,我们得用上 ES6 的解构赋值语法,因此得配合 babel 辅助开发。

在目录下我们新建一个 babel 配置“.babelrc”:

以及 rollup 配置“rollup.comfig.js”:

其中入口文件为“src/jquery.js”,并将以 umd 模式输出到 rel 文件夹下。

别忘了确保已安装了三大套:

后续咱们直接执行:

即可实现打包。

2. 模块拆分

从模块功能性入手,我们暂时先简单地把上次的整个 IIFE 代码段拆分为:

它们的内容分别如下:

jquery.js:

core.js:

init.js:

global.js:

留意在 global.js 中我们先加了一层判断,如果使用者走的模块化形式,那是无须考虑全局变量冲突处理的,直接绕过该模块即可。

执行打包后效果如下(rel/jquery.js)

3. extend 完善

如上章所说,我们可以通过 $.extend / $.fn.extend 接口来扩展 JQ 的静态方法/实例方法,也可以简单地实现对象的合并和深/浅拷贝。这是非常重要且实用的功能,在这里我们得完善它。

core.js 中我们新增如下代码段:

该段代码可以判断如下写法并做对应处理:

其它情况会被绕过(返回空对象)

我们继续完善内部的遍历:

这里需要留意的有,我们会通过

来递归生成被合并的 target 属性值,这是为了避免扩展后的 target 属性和被扩展的 copyObj 属性引用了同一个对象,导致互相影响。

通过 extend 递归解剖 copyObj 源对象的属性直到最内层,最内层属性的值(上方代码里的 copy)大致有这么两种情况:

1. copy 为空对象/空数组:

2. copy 为非对象(如“vajoy”):

从而确保 target 所扩展的每一层属性都跟 copyObj 的是互不关联的。

4. 建立基础工具模块

在上方的 extend 代码块中其实存在两个不合理的地方:

1. 仅通过 Object.toString.call(obj) === “[object Object]” 作为对象判断条件在我们扩展对象的逻辑中有些片面,适合扩展的对象应当是“纯粹/简单”(plain)的 js Object 对象,但在某些浏览器中,像 document 在 Object.toSting 调用时也会返回和 Object 相同结果;
2. 像 Object.hasOwnProperty 和 Object.prototype.toString.call 等方法在我们后续开发中会经常使用上,如果能把它们写到一个模块中封装起来复用就更好了。

关于 plainObject 的概念可以点这里了解。

基于上述两点,我们新增一个 util.js 来封装这些常用功能接口:

然后在 core.js 导入所需接口即可:

我们进一步修改 extend 接口代码为:

这里我们新增了isArray、isPlainObject 两个 jQuery 静态方法,其中 isPlainObject 比较有趣,为了过滤某些浏览器中的 document 等特殊类型,会对 obj.prototype 及其构造函数进行判断:

关于第二点,实际是直接判断两个构造器字符串化后是否相同:

我们执行打包处理:

在 HTML 页面运行下述代码:

效果如下:

留意 $.type 静态方法是我们上方通过 jQuery.extend 扩展进去的:

它返回传入参数的类型(小写)。该方法在我们下一章也会直接在模块中使用到。

本章先这样吧,得感谢这台风天赏赐了一天的假期,才有了时间写文章,共勉~

1 2 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部