javascript模块化是什么及其优缺点介绍

JavaScript017

javascript模块化是什么及其优缺点介绍,第1张

模块化的优缺点:

a>优点:

可维护性

1.灵活架构,焦点分离

2.方便模块间组合、分解

3.方便单个模块功能调试、升级

4.多人协作互不干扰

可测试性

1.可分单元测试

b>缺点:

性能损耗

1.系统分层,调用链会很长

2.模块间通信,模块间发送消息会很耗性能

3)最近的项目中也有用到模块化,

使用的是seajs,但是当引用到jquery,jquery easyui/或者jquery

UI组件时,有可能会用到很多jquery插件,那这样要是实现一个很复杂的交互时,模块间的依赖会很多,使用define()方法引入模块会很多,不知

有么有什么好的方法

前端模块化

在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即可;如今CPU、浏览器性能得到了极大的提升,很多页面逻辑迁移到了客户端(表单验证等),随着web2.0时代的到来,Ajax技术得到广泛应用,jQuery等前端库层出不穷,前端代码日益膨胀

这时候JavaScript作为嵌入式的脚本语言的定位动摇了,JavaScript却没有为组织代码提供任何明显帮助,甚至没有类的概念,更不用说模块(module)了,JavaScript极其简单的代码组织规范不足以驾驭如此庞大规模的代码

模块

既然JavaScript不能handle如此大规模的代码,我们可以借鉴一下其它语言是怎么处理大规模程序设计的,在Java中有一个重要带概念——package,逻辑上相关的代码组织到同一个包内,包内是一个相对独立的王国,不用担心命名冲突什么的,那么外部如果使用呢?直接import对应的package即可

import java.util.ArrayList

遗憾的是JavaScript在设计时定位原因,没有提供类似的功能,开发者需要模拟出类似的功能,来隔离、组织复杂的JavaScript代码,我们称为模块化。

一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。模块开发需要遵循一定的规范,各行其是就都乱套了

规范形成的过程是痛苦的,前端的先驱在刀耕火种、茹毛饮血的阶段开始,发展到现在初具规模,简单了解一下这段不凡的历程

函数封装

我们在讲函数的时候提到,函数一个功能就是实现特定逻辑的一组语句打包,而且JavaScript的作用域就是基于函数的,所以把函数作为模块化的第一步是很自然的事情,在一个文件里面编写几个相关函数就是最开始的模块了

function fn1(){

statement

}

function fn2(){

statement

}

这样在需要的以后夹在函数所在文件,调用函数就可以了

这种做法的缺点很明显:污染了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间没什么关系。

对象

为了解决上面问题,对象的写法应运而生,可以把所有的模块成员封装在一个对象中

var myModule = {

var1: 1,

var2: 2,

fn1: function(){

},

fn2: function(){

}

}

这样我们在希望调用模块的时候引用对应文件,然后

myModule.fn2()

这样避免了变量污染,只要保证模块名唯一即可,同时同一模块内的成员也有了关系

看似不错的解决方案,但是也有缺陷,外部可以随意修改内部成员

myModel.var1 = 100

这样就会产生意外的安全问题

立即执行函数

可以通过立即执行函数,来达到隐藏细节的目的

var myModule = (function(){

var var1 = 1

var var2 = 2

function fn1(){

}

function fn2(){

}

return {

fn1: fn1,

fn2: fn2

}

})()

这样在模块外部无法修改我们没有暴露出来的变量、函数

上述做法就是我们模块化的基础,目前,通行的JavaScript模块规范主要有两种:CommonJS和AMD

CommonJS

我们先从CommonJS谈起,因为在网页端没有模块化编程只是页面JavaScript逻辑复杂,但也可以工作下去,在服务器端却一定要有模块,所以虽然JavaScript在web端发展这么多年,第一个流行的模块化规范却由服务器端的JavaScript应用带来,CommonJS规范是由NodeJS发扬光大,这标志着JavaScript模块化编程正式登上舞台。

定义模块

根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性

模块输出:

模块只有一个出口,module.exports对象,我们需要把模块希望输出的内容放入该对象

加载模块:

加载模块使用require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象

一、Javascript模块化编程

目前,通行的Javascript模块规范共有两种:CommonJS和AMD。

1、commonjs

2009年,美国程序员Ryan Dahl创造了node.js项目,将javascript语言用于服务器端编程,这标志”Javascript模块化编程”正式诞生。

在浏览器环境下,没有模块也不是特别大的问题,毕竟网页程序的复杂性有限;但是在服务器端,一定要有模块,与操作系统和其他应用程序互动,否则根本没法编程。

node.js的模块系统,就是参照CommonJS规范实现的。在CommonJS中,有一个全局性方法require(),用于加载模块。

假定有一个数学模块math.js,就可以像下面这样加载。

var math = require('math')

然后,就可以调用模块提供的方法:

var math = require('math')

math.add(2,3)// 5

因为这个系列主要针对浏览器编程,不涉及node.js,所以对CommonJS就不多做介绍了。我们在这里只要知道,require()用于加载模块就行了。

2、AMD

AMD是”Asynchronous Module Definition”的缩写,意思就是”异步模块定义”。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

模块定义

define(id?, dependencies?, factory)

其中:

id: 模块标识,可以省略。

dependencies: 所依赖的模块,可以省略。

factory: 模块的实现,或者一个JavaScript对象。

模块加载

AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:

require([module], callback)

第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。如果将前面的代码改写成AMD形式,就是下面这样:

require(['math'], function (math) {

math.add(2, 3)

})

math.add()与math模块加载不是同步的,浏览器不会发生假死。所以很显然,AMD比较适合浏览器环境。

目前,主要有两个Javascript库实现了AMD规范:require.js和curl.js。本系列的第三部分,将通过介绍require.js,进一步讲解AMD的用法,以及如何将模块化编程投入实战。

二、requirejs模块化编程

require.js加载的模块,采用AMD(异步模块定义规范) 规范。也就是说,模块必须按照AMD的规定来写。

require.js的两个重要的特点:

1、实现js文件的异步加载,避免网页失去响应

2、管理模块之间的依赖性,便于代码的编写和维护

加载requirejs:

<script src="js/require.js" data-main="js/main"></script>

data-main属性的作用是,指定网页程序的主模块。在上例中,就是js目录下面的main.js,这个文件会第一个被require.js加载。由于require.js默认的文件后缀名是js,所以可以把main.js简写成main。

main.js常见实例:

require.config({

paths: {

moduleA: '',

moduleB:'',

moduleC:''

}

})

require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){

// some code here

})

1、require.config

require.config用来配置一些参数,它将影响到requirejs库的一些行为。

require.config的参数是一个JS对象,常用的配置有baseUrl,paths等。

这里配置了paths参数,使用模块名“jquery”,其实际文件路径jquery-1.7.2.js(后缀.js可以省略)。

我们知道jQuery从1.7后开始支持AMD规范,即如果jQuery作为一个AMD模块运行时,它的模块名是“jquery”。注意“jquery”是固定的,不能写“jQuery”或其它。

注:如果文件名“jquery-1.7.2.js”改为“jquery.js”就不必配置paths参数了。

如果将jQuery应用在模块化开发时,其实可以不使用全局的,即可以不暴露出来。需要用到jQuery时使用require函数即可。

2、require()函数

require()函数接受两个参数。第一个参数是一个数组,表示所依赖的模块,上例就是['moduleA', 'moduleB',

'moduleC'],即主模块依赖这三个模块;第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。