前言

前端开发中,起初只要在script标签中嵌入几十上百行代码就能实现一些基本的交互效果,后来js得到重视,应用也广泛起来了,jQuery,Ajax,Node.Js,MVC,MVVM等的助力也使得前端开发得到重视,也使得前端项目越来越复杂,然而,JavaScript却没有为组织代码提供任何明显帮助,甚至没有类的概念,更不用说模块(module)了,所以,进行模块化开发的重要性就不言而喻了。那么什么是模块呢?

一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。

所以,今天小编介绍一下js模块化开发的几种方法。

一、模块化开发规范

js模块化的开发并不是随心所欲的,为了便于他人的使用和交流,需要遵循一定的规范。目前,通行的js模块规范主要有两种:CommonJSAMD

1.1AMD

AMD 即Asynchronous Module Definition,中文名是“异步模块定义”的意思。它是一个在浏览器端模块化开发的规范,服务器端的规范是CommonJS;

模块将被异步加载,模块加载不影响后面语句的运行。所有依赖某些模块的语句均放置在回调函数中。

关于AMD有两个非常重要的概念,那就是用于模块定义的define方法和用于处理依赖加载的require方法。

(1)作为一个规范,只需定义其语法API,而不关心其实现。define函数定义如下:

 define(
[module-name?] /*可选*/,
[array-of-dependencies?] /*可选*/,
[module-factory-or-object]
);
其中:
  • module-name: 模块标识,可以省略。如果没有这个属性,则称为匿名模块。
  • array-of-dependencies: 所依赖的模块,可以省略。
  • module-factory-or-object: 模块的实现,或者一个JavaScript对象

举个栗子:

define(
"myModule",
["foo", "bar"], // 模块定义函数,依赖(foo,bar)作为参数映射到函数上
function (foo, bar) {
// 创建模块
var myModule = {
myFun: function () {
console.log("Jeri");
}
} // 返回定义的模块
return myModule;
}
);

(2)require()方法,有两个参数:

require([module], callback);

其中:

  • 第一个参数[module],是一个数组,里面的成员就是要加载的模块;
  • 第二个参数callback,则是加载成功之后的回调函数。

举个实际栗子:

 require(['math'], function (math) {
    math.add(2, 3);
  });

1.2CommonJS规范

CommonJS是服务器端模块的规范,根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性。输出模块变量的最好方法是使用module.exports对象。

不过,与AMD表现形式不同的是,CommonJS模块并不使用define进行定义。CommonJS模块由两部分组成:变量exports和require函数。

(1)exports/require:加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的module.exports对象。

再举个栗子:创建两个js文件:

libJS:

 // 新定义的模块方法
function log(arg) {
console.log(arg);
} // 把方法暴露给其他模块
exports.log = log;

app.JS:

 // ./lib是我们需要的一个依赖
var lib = requrie("./lib"); // 新定义的模块方法
function foo() {
lib.log("jeri");
} // 把方法暴露给其他模块
exports.foo = foo;

(2)module.exports

直接举栗子:

 var i = 1;
var max = 30; module.exports = function () {
for (i -= 1; i++ < max; ) {
console.log(i);
}
max *= 1.1;
};
二、JS模块的常用写法

在前言中小编也提过,模块:就是一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。

除了接下来要讲的require.js,还有适合于一些简单模块的几种常用写法。

2.1字面量写法

要知道,模块就是实现特定功能的一组方法。

只要把不同的函数(以及记录状态的变量)简单地放在一起,就算是一个模块。这也是最简单的一种写法。也就是说,每一个函数就是一个简单的模块。

 function func1 (){
alert("这是func1");
};
function func2 (){
alert("这是func2");
}

把栗子中的两个函数func1()和func2()就组成了一个模块;

不过,这种写法有着一定的缺点:

如果只是实现一些简单的功能还好,如果实现复杂的功能,太多的函数就会出现问题,"污染"了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。

2.2对象写法

所以,为了解决上述的问题,把模块写成一个对象,所有的模块成员都放到这个对象里面不失为一个好的方式。

再再举个栗子:

 var module = {
func1 : function(){
alert(1);
} func2 : function(){
alert(2);
}
} module.func1();
module.func2();

2.3通过闭包实现

在JavaScript中,并不能可以直接声明类,但我们可以使用闭包来封装私有的属性和方法,进而模拟类的概念,在JavaScript中实现Module模式;

疯狂的举栗子:

 var myModule = (function () {

     // 私有变量
var privateVar = 0; // 私有函数
var privateFun = function (foo) {
console.log(foo);
}; return {
// 私有变量
publicVar: "foo", // 公有函数
publicFun: function (arg) { // 修改私有变量
privateVar ++; // 传入bar调用私有方法
privateFun(arg);
}
};
}) ()

2.4输入全局变量

独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互。为了在模块内部调用全局变量,必须显式地将其他变量输入模块。

 var module1 = (function ($, YAHOO) {
    //...
  })(jQuery, YAHOO);
三、require.js

requir.JS本就是为了实现js的模块开发而创建的一个js脚本,其主要有着两大优点:

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

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

3.1require.js的实现步骤

(1)众所周知,要导入js文件,为了避免网页失去响应有两种方法;

第一种,把<script></script>放在文件的最后。

今天,我们主要说第二种:

 <script src="js/require.js" defer async="true" ></script>

async属性表明这个文件需要异步加载,避免网页失去响应。但是,IE不支持这个属性,只支持defer,所以需要把defer也写上。

(2)在HTML中导入require.JS文件后,就可以编写自己的main.js文件。

首先,导入main.js文件:

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

其中:data-main属性的作用是,指定网页程序的主模块。

在上例中,就是js目录下面的main.js,这个文件会第一个被require.js加载。由于require.js默认的文件后缀名是js,所以可以把main.js简写成main。

(3)编写main.js;

  require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
    // some code here
  });

通过require方法,实现代码的模块加载,传入两个参数:

①第一个参数是一个数组,表示代码所依赖的模块。
②第二个参数是一个回调函数,当前面的模块加载完成后,就会被调用。
加载的模块一参数的形式传入,从而在回调函数内部可以使用这些模块,回调函数就是整个页面的JS代码;

再次疯狂的举栗子:

 require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone){
    // some code here
  });

3.2模块的加载

在上面的栗子中,我们可以使用require.config()方法,对模块的加载行为进行自定义。

(1)require.config()就写在主模块(main.js)的头部。参数就是一个对象,这个对象的paths属性指定各个模块的加载路径。

不要命的举栗子:

 require.config({
    paths: {
      "jquery": "jquery.min",
      "underscore": "underscore.min",
      "backbone": "backbone.min"
    }
  });

(2)上面的代码给出了三个模块的文件名,路径默认与main.js在同一个目录(js子目录)。

如果这些模块在其他目录,比如js/lib目录,则有两种写法。

一种是逐一指定路径。

再次举栗子:

 require.config({
    paths: {
      "jquery": "lib/jquery.min",
      "underscore": "lib/underscore.min",
      "backbone": "lib/backbone.min"
    }
  });

另一种则是直接改变基目录(baseUrl)。

再再次举栗子:

 require.config({
    baseUrl: "js/lib",
    paths: {
      "jquery": "jquery.min",
      "underscore": "underscore.min",
      "backbone": "backbone.min"
    }
  });

(3)如果某个模块在另一台主机上,也可以直接指定它的网址;

举栗子:

require.config({
    paths: {
      "jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"
    }
  });

3.3require的AMD模块写法

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

具体来说,就是模块必须采用特定的define()函数来定义。如果一个模块不依赖其他模块,那么可以直接定义在define()函数之中。

假定现在有一个math.js文件,它定义了一个math模块。那么,math.js就要这样写:

 // math.js

   define(function (){

     var add = function (x,y){

       return x+y;

     };

     return {

       add: add
    };   });

加载方法如下:

 // main.js

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

     alert(math.add(1,1));

   });

如果这个模块还依赖其他模块,那么define()函数的第一个参数,必须是一个数组,指明该模块的依赖性。

  define(['myLib'], function(myLib){

     function foo(){

       myLib.doSomething();

     }

     return {

       foo : foo

     };

   });
作者编

在日常的工作中,js的模块法开发是一个不可或缺的一部分。在这里只是介绍了基于AMD模块的require.js。还有基于commonJS规范的node.js。小编会在下次和大家一起学习。

JS模块化开发----require.js的更多相关文章

  1. js模块化开发——require.js的用法详细介绍(含jsonp)

    RequireJS的目标是鼓励代码的模块化,它使用了不同于传统<script>标签脚本加载步骤.可以用它回事.优化代码,但其主要的目的还是为了代码的模块化.它鼓励在使用脚本以moudle ...

  2. js模块化开发——require.js学习总结

    1.为什么使用require.js 作为命名空间: 作为命名空间使用: 异步加载js,避免阻塞,提高性能: js通过require加载,不必写很多script 2.require.js的加载 requ ...

  3. js模块化开发——require.js的实战写法1

    关于在Require.js使用一个JS插件的问题 我需要在项目中引用一个js控件,这个控件依赖于a.js,b.js,c.js,.....n.js N多个js以及jquery及jquery-ui,各js ...

  4. js模块化开发——require.js的用法

    这个系列的第一部分和第二部分,介绍了Javascript模块原型和理论概念,今天介绍如何将它们用于实战. 我采用的是一个非常流行的库require.js. 一.为什么要用require.js? 最早的 ...

  5. JS模块化工具require.js教程(一):初识require.js

    随着网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式,我们需要团队协作.模块复用.单元测试等等一系列复杂的需求 ...

  6. JS模块化工具require.js教程(二):基本知识

    前一篇:JS模块化工具我们以非常简单的方式引入了requirejs,这一篇将讲述一下requirejs中的一些基本知识,包括API使用方式等 基本API require会定义三个变量:define,r ...

  7. JS模块化开发:使用SeaJs高效构建页面

    一.扯淡部分 很久很久以前,也就是刚开始接触前端的那会儿,脑袋里压根没有什么架构.重构.性能这些概念,天真地以为前端===好看的页面,甚至把js都划分到除了用来写一些美美的特效别无它用的阴暗角落里,就 ...

  8. JS模块化开发(三)——seaJs+grunt

    1.seaJs直接构建存在的问题 由于模块之间的依赖require引用的是模块名,当多个js模块被合并成一个时,会由于找不到模块名而报错 2.seaJs+grunt开发 用到的插件:grunt-cmd ...

  9. Js模块化开发的理解

    Js模块化开发的理解 模块化是一个语言发展的必经之路,其能够帮助开发者拆分和组织代码,随着前端技术的发展,前端编写的代码量也越来越大,就需要对代码有很好的管理,而模块化能够帮助开发者解决命名冲突.管理 ...

随机推荐

  1. Prison Break

    Prison Break 时间限制: 1 Sec  内存限制: 128 MB提交: 105  解决: 16[提交][状态][讨论版] 题目描述 Scofild又要策划一次越狱行动,和上次一样,他已经掌 ...

  2. Python打印乘法口诀表

    思路:第一行:1*1,第二行:1*2.,2*2,第三行:1*3,2*3,3*3-- 最后一行:1*9,2*9,3*9,-9*9,以此类推,可以设2个数:i,j:让 i 从1循环到9,让 j 从1到小于 ...

  3. 【vue系列之二】详解vue-cli 2.0配置文件

    上次给大家分享的是用vue-cli快速搭建vue项目,虽然很省时间和精力,但想要真正搞明白,我们还需要对其原理一探究竟. 大家拿到一个项目,要快速上手,正确的思路是这样的: 首先,如果在项目有read ...

  4. 我的第一个python web开发框架(6)——第一个Hello World

    小白中午听完老菜讲的那些话后一直在思考,可想来想去还是一头雾水,晕晕呼呼的一知半解,到最后还是想不明白,心想:老大讲的太高深了,只能听懂一半半,看来只能先记下来,将明白的先做,不明白的等以后遇到再学. ...

  5. 数据库中删除语句Drop、Delete、Truncate的相同点和不同点的比较

    数据库删除语句的分别介绍: Delete:用于删除表中的行(注:可以删除某一行:也可以在不删除表的情况下(即意味着表的结构.属性.索引完整)删除所有行) 语法:删除某一行:Delete From 表名 ...

  6. Jquery 使用Ajax获取后台返回的Json数据后,页面处理

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. [js高手之路]匀速运动与实例实战(侧边栏,淡入淡出)

    javascript中,如何让一个元素(比如div)运动起来呢? 设置基本的样式,一定要让div有定位( 当然用margin的变化也可以让元素产生运动效果 ); <style> div { ...

  8. Bootstrap表格样式(附源码文件)--Bootstrap

    1.表格默认样式 <h4>表格默认样式</h4><table><!--默认样式--> <tr><th>序号</th> ...

  9. C#基础之转换

    C#中一共有两种转换方式,隐式转换和显示转换 隐式转换:就是不需要声明就能进行的转换,通俗来说就是小范围内的数据类型转大范围数据类型 显示转换:就是通常说的强制转换,需要在代码中写明要的数据类型.通俗 ...

  10. visio移动形状 上下左右键 移动滚动条

    今天在用visio写作业,想微移visio的形状,于是按上下左右方向键,结果移动的是滚动条. 那么如何让visio按上下左右移动的是形状,其实按Scroll键就好了.