前端模块化

《源码学习之前端模块化》

1. 什么是模块化

2. 为什么需要模块化

3. 源码中的模块化

3.1 AMD

3.2 Commonjs

3.3 Vue源码解析之模块化

1. 什么是模块化

模块化并不是前端独有的思想。模块化是一种自顶向下的过程,通过把一个大的系统,逐步划分为一个个小的模块,这些模块内部封装了一些特定的功能,通过约定的接口对外暴露。各个模块之间互不干扰,易于插拔。 模块化可以解耦代码,更好地进行复用,每个模块之间互不影响,不用担心变量污染、命名冲突等问题,同时也有利于并行开发,提升效率。

js最初是没有模块化的。随着前端应用越来越复杂,比如,当一个html页面要请求多个js文件时,如何保证这些js文件之间的变量互不干扰?为了解决诸如变量污染、命名冲突的问题,js开始出现了一些模块化的方案,从2003年提出的闭包模块化,再到2009年的CommonJS和AMD,以及如今的ES模块化。

2. 为什么需要模块化

模块化的好处可以总结为以下几点:

拥有独立作用域,避免变量污染、命名冲突

降低项目复杂度,提高开发效率

提升代码可复用性和可维护性

3. 源码中的模块化

在上述提到的AMD和Commonjs规范,对于模块化的定义不尽相同,在进行模块化时需要对不同环境进行兼容处理。

3.1 AMD

AMD(Asynchronous Module Definition),异步模块定义。在加载模块以及模块所依赖的其它模块时,AMD都采用异步加载的方式,避免模块加载阻塞网页渲染。

AMD作为一个规范,只需定义其语法API,而不关心其实现。AMD规范简单到只有一个API,即模块定义define函数:

define(name?, [dependencies]?, factory)

name是模块的标识,如果未提供则以文件名为标识;

dependencies表示所依赖的模块;

factory是模块初始化要执行的函数或对象,如果是函数,只执行一次,如果是对象,即为模块输出值。

AMD规范主要是针对前端浏览器的规范。

3.2 Commonjs

CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

CommonJS规范加载模块是同步加载的,也就是说,只有加载完成,才能执行后面的操作。

模块定义语法: module.exports=factory()

CommonJS主要是针对浏览器之外的js环境的规范。

3.3 Vue源码解析之模块化

以vue2的源码为例,将源码折叠后你会看到如下代码: 


这是一个匿名自执行函数,这个匿名函数拥有独立的作用域,既避免污染外界代码,也避免被外界代码污染。

如果需要用到外界的全局变量,可以通过参数传入,如图中的this,这个this实际上是Window对象,通过传入 this,使得Window由全局变量变为局部变量,当在后面那个代码块中访问 this时,不需要将作用域链回退到顶层作用域,这样可以更快的访问Window对象;将 Window作为参数传入,也可以在压缩代码时进行优化。如:(function(a,b){})(window); // window 被优化为 a。

global即自执行传进来的this参数,也就是Window对象。

factory即传进来的第二个参数,也就是后面那个匿名函数。

展开第一个function可以看到如下代码:

typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :

    typeof define === 'function' && define.amd ? define(factory) :

      (global = global || self, global.Vue = factory());

这段代码的作用是检测当前的运行环境支持哪种模块化规范,然后将Vue模块化,其中exports是Commonjs规范,define是AMD的规范。

在源码中可以看到,factory()最后return的是一个Vue对象。

当检测出为Commonjs规范时,导出Vue对象的写法为:

module.exports = factory();

当检测出为AMD规范时,写法为:

define(factory)。

为了更直观,改写一下这段代码:

if(typeof exports === 'object' && typeof module !== 'undefined'){

    // Commonjs规范

    module.exports = factory();

}else if(typeof define === 'function' && define.amd){

    // AMD规范

    define(factory);

}else{

    // 其他情况下,将Vue挂载到全局对象中

    // 在浏览器里就是给Window对象添加Vue属性,属性值为factory()返回的Vue对象

    global = global || self,

    global.Vue = factory();

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355