了解Javascript的模块化开发


Posted in Javascript onMarch 02, 2015

小A是某个创业团队的前端工程师,负责编写项目的Javascript程序。

全局变量冲突

根据自己的经验,小A先把一些常用的功能抽出来,写成函数放到一个公用文件base.js中:

var _ = {

    $: function(id) { return document.getElementById(id); },

    getCookie: function(key) { ... },

    setCookie: function(key, value) { ... }

};

小A把这些函数都放在_对象内,以防过多的全局变量造成冲突。他告诉团队的其他成员,如果谁想使用这些函数,只要引入base.js就可以了。

小C是小A的同事,他向小A反映:自己的页面引入了一个叫做underscore.js的类库,而且,这个类库也会占用_这个全局变量,这样一来就会跟base.js中的_冲突了。小A心想,underscore.js是第三方类库,估计不好改,但是base.js已经在很多页面铺开,不可能改。最后小A只好无奈地把underscore.js占用的全局变量改了。

此时,小A发现,把函数都放在一个名字空间内,可以减少全局变量冲突的概率,却没有解决全局变量冲突这个问题。

依赖

随着业务的发展,小A又编写了一系列的函数库和UI组件,比方说标签切换组件tabs.js,此组件需调用base.js以及util.js中的函数。

有一天,新同事小D跟小A反映,自己已经在页面中引用了tabs.js,功能却不正常。小A一看就发现问题了,原来小D不知道tabs.js依赖于base.js以及util.js,他并没有添加这两个文件的引用。于是,他马上进行修改:

<script src="tabs.js"></script>

<script src="base.js"></script>

<script src="util.js"></script>

然而,功能还是不正常,此时小A教训小D说:“都说是依赖,那被依赖方肯定要放在依赖方之前啊”。原来小D把base.js和util.js放到tabs.js之后了。

小A心想,他是作者,自然知道组件的依赖情况,但是别人就难说了,特别是新人。

过了一段时间,小A给标签切换组件增加了功能,为了实现这个功能,tabs.js还需要调用ui.js中的函数。这时,小A发现了一个严重的问题,他需要在所有调用了tabs.js的页面上增加ui.js的引用!!!

又过了一段时间,小A优化了tabs.js,这个组件已经不再依赖于util.js,所以他在所有用到tabs.js的页面中移除了util.js的引用,以提高性能。他这一修改,出大事了,测试组MM告诉他,有些页面不正常了。小A一看,恍然大悟,原来某些页面的其他功能用到了util.js中的函数,他把这个文件的引用去掉导致出错了。为了保证功能正常,他又把代码恢复了。

小A又想,有没有办法在修改依赖的同时不用逐一修改页面,也不影响其他功能呢?

模块化

小A逛互联网的时候,无意中发现了一种新奇的模块化编码方式,可以把它之前遇到的问题全部解决。

在模块化编程方式下,每个文件都是一个模块。每个模块都由一个名为define的函数创建。例如,把base.js改造成一个模块后,代码会变成这样:

define(function(require, exports, module) {

    exports.$ = function(id) { return document.getElementById(id); };

    exports.getCookie = function(key) { ... };

    exports.setCookie = function(key, value) { ... };

});

base.js向外提供的接口都被添加到exports这个对象。而exports是一个局部变量,整个模块的代码都没有占用半个全局变量。

那如何调用某个模块提供的接口呢?以tabs.js为例,它要依赖于base.js和util.js:

define(function(require, exports, module) {

    var _ = require('base.js'), util = require('util.js');

    var div_tabs = _.$('tabs');

    // .... 其他代码

});

一个模块可以通过局部函数require获取其他模块的接口。此时,变量_和util都是局部变量,并且,变量名完全是受开发者控制的,如果你不喜欢_,那也可以用base:
define(function(require, exports, module) {

    var base = require('base.js'), util = require('util.js');

    var div_tabs = base.$('tabs');

    // .... 其他代码

});

一旦要移除util.js、添加ui.js,那只要修改tabs.js就可以了:
define(function(require, exports, module) {

    var base = require('base.js'), ui = require('ui.js');

    var div_tabs = base.$('tabs');

    // .... 其他代码

});

加载器

由于缺乏浏览器的原生支持,如果我们要用模块化的方式编码,就必须借助于一个叫做加载器(loader)的东西。

目前加载器的实现有很多,比如require.js、seajs。而JRaiser类库也有自己的加载器。

Javascript 相关文章推荐
去除链接虚线全面分析总结
Aug 15 Javascript
Jquery 获得服务器控件值的方法小结
May 11 Javascript
javascript中数组的sort()方法的使用介绍
Dec 18 Javascript
jQuery分组选择器用法实例
Dec 23 Javascript
JavaScript html5 canvas画布中删除一个块区域的方法
Jan 26 Javascript
Webpack打包慢问题的完美解决方法
Mar 16 Javascript
javascript回调函数的概念理解与用法分析
May 27 Javascript
解决vue中修改export default中脚本报一大堆错的问题
Aug 27 Javascript
layui 图片上传+表单提交+ Spring MVC的实例
Sep 21 Javascript
Vue使用NProgress的操作过程解析
Oct 10 Javascript
使用jquery实现轮播图效果
Jan 02 jQuery
Vue和Flask通信的实现
May 19 Vue.js
JS实现的4种数字千位符格式化方法分享
Mar 02 #Javascript
js实现图片漂浮效果的方法
Mar 02 #Javascript
ECMAScript 5中的属性描述符详解
Mar 02 #Javascript
JS+CSS实现可以凹陷显示选中单元格的方法
Mar 02 #Javascript
JavaScript数组常用方法
Mar 02 #Javascript
使用npm发布Node.JS程序包教程
Mar 02 #Javascript
js实现点击链接后窗口缩小并居中的方法
Mar 02 #Javascript
You might like
php打开本地exe程序,js打开本地exe应用程序,并传递相关参数方法
2018/02/06 PHP
laravel框架数据库操作、查询构建器、Eloquent ORM操作实例分析
2019/12/20 PHP
javascript HTMLEncode HTMLDecode的完整实例(兼容ie和火狐)
2009/06/02 Javascript
学习JS面向对象成果 借国庆发布个最新作品与大家交流
2009/10/03 Javascript
JS Loading功能的简单实现
2013/11/29 Javascript
JQuery中使用Ajax赋值给全局变量异常的解决方法
2014/01/10 Javascript
jQuery中addClass()方法用法实例
2015/01/05 Javascript
jQuery统计指定子元素数量的方法
2015/03/17 Javascript
在JavaScript中操作数组之map()方法的使用
2015/06/09 Javascript
jquery实现全屏滚动
2015/12/28 Javascript
JQuery在循环中绑定事件的问题详解
2016/06/02 Javascript
微信小程序上滑加载下拉刷新(onscrollLower)分批加载数据(二)
2017/05/11 Javascript
详解vue 模拟后台数据(加载本地json文件)调试
2017/08/25 Javascript
vuex直接赋值的三种方法总结
2018/09/16 Javascript
基于Vue的商品主图放大镜方案详解
2019/09/19 Javascript
如何在vue中使用百度地图添加自定义覆盖物(水波纹)
2020/11/03 Javascript
微信小程序实现购物车功能
2020/11/18 Javascript
[01:06:43]完美世界DOTA2联赛PWL S3 PXG vs GXR 第二场 12.19
2020/12/24 DOTA
Python实现快速排序算法及去重的快速排序的简单示例
2016/06/26 Python
Python的SQLalchemy模块连接与操作MySQL的基础示例
2016/07/11 Python
django框架使用方法详解
2019/07/18 Python
python 函数嵌套及多函数共同运行知识点讲解
2020/03/03 Python
基于Pyinstaller打包Python程序并压缩文件大小
2020/05/28 Python
Pycharm创建python文件自动添加日期作者等信息(步骤详解)
2021/02/03 Python
一款基于css3麻将筛子3D翻转特效的实例教程
2014/12/31 HTML / CSS
使用HTML5 IndexDB存储图像和文件的示例
2018/11/05 HTML / CSS
英国最受欢迎的在线隐形眼镜商店:VisionDirect.co.uk
2018/12/06 全球购物
马来西亚在线购物:POPLOOK.com
2019/12/09 全球购物
求职者简历中的自我评价
2013/10/20 职场文书
项目经理的岗位职责
2013/11/23 职场文书
前台接待岗位职责
2013/12/03 职场文书
总经理岗位职责范本
2014/02/02 职场文书
教师个人发展总结
2015/02/11 职场文书
毕业班工作总结
2015/08/10 职场文书
《秋天的怀念》教学反思
2016/02/17 职场文书
python套接字socket通信
2022/04/01 Python