什么是js模块化编程?
为什么要引入模块化编程?
一、模块化编程概念
模块,在这里就是指一个具有单 一职责功能的js文件。我们通过相互引用,将这些有单 一职责功能的js组织起来,实现某一功能,就是所谓的模块化编程。模块化编程要求每个js文件都职责单 一,大大增强代码的可读性、易维护性、可扩展性、减少全局污染等。
二、传统前端js编程方式
实例:我们在一个html页面显示出hello Word+当前年。
html代码,如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>helloWord</title> </head> <body> <div> <textarea rows="2" cols="12" id="say"></textarea> </div> </body> <script src="lib/jquery.min.js"></script> <script type="text/javascript" src="utils.js"></script> <script type="text/javascript" src="helloWord.js"></script> </html>
上面html中我们通过<script>标签引入了,3个js文件。一个是jquery类库,utils.js是一个工具类,可返回当前年份,helloWord.js作用是输出文件到id=say的<textarea>标签。引入的js文件如下:
utils.js
$(function($){ utils = function() { }; utils.prototype = { getCurrentYear : function(){ var rq = new Date(); return rq.getFullYear(); } } });
helloWord.js
$(function($){ var u = new utils(); $("#say").text("hello Word:"+u.getCurrentYear()); });
上面实例的写法是模块化编程出现前,我们最常用的写法。但这种实现方法常常引发一些问题,让我们难以解决。
1、js依赖管理问题:通过<script>标签加载js时,我们必须非常明确的知道,加载的js,它引用了哪些js。并在加载前,将它所依赖的js全部都先用<script>标签引入。就像实例中helloWord.js,它调用了utils.js中的方法,那么我们就必须先加载utils,再加载helloWord的js文件,否则执行js就会出现如下找不到的错误。
helloWord.js:2 Uncaught ReferenceError: utils is not defined at HTMLDocument.<anonymous> (helloWord.js:2) at j (jquery.min.js:2) at Object.fireWith [as resolveWith] (jquery.min.js:2) at Function.ready (jquery.min.js:2) at HTMLDocument.I (jquery.min.js:2)
当一个页面加载的js只有几个时,可能管理起来不是很麻烦,但当一个页面很复,需要引入的js达到几十个时,这时你要去确定先先加载谁慢加载就是一个很困难的工作了。
2、不能异步按需加载js文件:当浏览器在解析html的过程中遇到了<script>标签,就会停止处理页面,先执行JavaScript代码,然后再继续解析和渲染页面。这样就是造成页面加载的中断,当中间加载的js比较多的时候,用户等待js加载的过程中就会出现显示空白的情况,体验很差。
我们在大型项目中,多项目组协同开发时,为了解决问题1中的提到的js依赖问题,往往会将一些基础的js例如工具类、控件类js按顺序封装在一起,同时加载。但有时候对于一些简单的功能可能只会用到里面的一小部分js文件,但却要加载一堆的js,很容易造成资源的良费。
3、全局变量冲突问题: 在非模块化编程前,我们的js经常会不得不定义一些全局的js变量,就如实例中utils.js中,就定义了全局变量utils,当很多人协同开发时,有可能别人也定义了同样的全局变量,当两个js都同时加载时,就会引发问题。
虽然这些问题,之前也有一些相应的解决办法,但都没有像模块化编程一样。模块化编程,使得js引用,可以像java 编程一样,想用哪个文件,直接导入即可。让前端开发人员无需再管理js之间复杂的依赖关系,真正做到了js的按需加载。