什么是模块化
模块就是实现特定功能的一组方法
常见的几种js写法
- 原始写法
function A() { } function B() { }
上面函数A()和B()组成一个模块,使用的时候直接调用就行了
缺点: “污染”了全局变量,模块成员之间没有直接的联系。
- 对象写法
var module= { count:1, A: function() { }, B: function() { } }
这种写法把变量count和函数A和 B 都封装到了module中,使用的时候直接调用,例如:
Module.A();
缺点:这种做法暴露了模块成员,内部的变量可以被外部改写,例如:
Module.count=5
- 立即执行函数写法
var modulel = (function() { var count = 5; var A = function() { console.log("function A"); }; var B = function() { console.log("function B"); }; return { A:A, B:B, count:count } })();
- 放大模式
如果一个模块很大,必须分成几个部分,则需要继承另外一个模块,则有必要使用“放大模式”
var commonUtil = (function (util) { util.m1 = function () { console.log("m1 function"); }; util.m2 = function () { console.log("m2 function"); }; util.count = 5; return util; })(commonUtil); console.log(commonUtil.m1()); console.log(commonUtil.count);
- 宽放大模式
var commonUtil = (function (util) { util.m1 = function () { console.log("m1 function"); }; util.m2 = function () { console.log("m2 function"); }; util.count = 5; return util; })(commonUtil || {}); console.log(commonUtil.m1()); console.log(commonUtil.count);
与“放大模式”相比,“宽放大模式”就是立即执行函数可以是空对象
为什么要用require.js
最早的时候,所有的javascript都是写在一个文件中,代码越来越多,则分成了多个,例如:
<script src="1.js"></script> <script src="2.js"></script> <script src="3.js"></script> <script src="4.js"></script> <script src="5.js"></script> <script src="6.js"></script>
这样做的缺点:
1)加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就越长
2)必须保证加载的顺序,依赖最大的模块一定要放到最后加载
Require.js就是为了解决这两个问题:
1) 实现js文件的异步加载,避免网页失去响应
2) 管理模块之间的依赖性,便于代码的编写和维护
Require.js加载
首先要到官方网站下载最新版本http://requirejs.org/docs/download.html放到Scripts目录下
然后在页面加载,例如:
<script src="Scripts/require.js"></script>
加载这个文件也有可能造成网页失去响应,解决办法有两个,一是把它放在网页底部加载,另外一个是写成这样:
<script src="Scripts/require.js" defer async="true" ></script>
Async表示是异步加载,ie不支持这个属性,只支持defer,所以把defer也写上
加载require.js之后,则是加载我们自己的代码了,假如我们自己的代码文件是main.js,则需要写成这样
<script src="Scripts/require.js" data-main="Scripts/main.js"></script>
data-main属性的作用是指定网页程序的主模板,就是网页的入口代码,有点像控制台程序的main()函数,所有的代码都是从这里开始运行
模块的加载
假如模块依赖’jquery’,’underscore’,’backbone’,则需要在require.config()方法中对这些模块进行配置
我们可以把require.config()写在主模块main.js的头部,也可以新建一个require_config.js文件把这些配置写在这个文件中,然后在页面引用这个文件,例如:
(function () { var baseurl = "/Scripts/"; require.config({ paths: { "jquery": baseurl+"jquery", "underscore": baseurl+"underscore", "backbone": baseurl+"backbone", "index":baseurl+"lib/index" }, shim: { ‘underscore‘: { exports: ‘_‘ }, ‘backbone‘: { deps: [‘underscore‘, ‘jquery‘], exports: ‘Backbone‘ } } }); })();
如果某个模块在另外的主机上,也可以指定网址,例如:
require.config({ paths: { "jquery":”https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min”, } });
require.js加载的模块,必须按照AMD规范,用define()函数定义的模块。但有一部分函数库并不符合这种规范,这种模块则必须在require()加载前,用shim属性进行配置,shim属性是用来配置不兼容的模块。
例如:
shim: { ‘underscore‘: { exports: ‘_‘ }, ‘backbone‘: { deps: [‘underscore‘, ‘jquery‘], exports: ‘Backbone‘ } }
其中
1) exports表示输出变量名,即在模块外部调用的名称
2) deps数组,表示该模块的依赖性
主模块的写法
require()函数接受两个参数,第一个参数是一个数组,表示所依赖的模块,第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数的形式传入该函数,而在回调函数中就可以使用这些模块了。
例如:主模块依赖jquery,underscore和backbone这三个模块,main.js就可以这样写:
require ([‘jquery‘, ‘underscore‘, ‘backbone‘], function ($, _, Backbone) { //some code here });
require.js会先加载jQuery,underscore和backbone,然后再运行回调函数,主模块的代码就写在回调函数中
AMD模块的写法
require.js加载的模块,采用AMD规范,模块也必须按照AMD来写,就是模块必须采用特定的define函数来定义,例如index.js:
define([‘jquery‘, ‘underscore‘, ‘backbone‘], function ($, _, Backbone) { var listView = { World: Backbone.Model.extend({ name: null }), Worlds: Backbone.Collection.extend({ initialize: function(models, options) { this.bind("add", options.view.addOneWord); } }), AppView: Backbone.View.extend({ el: $("body"), initialize: function() { this.worlds = new listView.Worlds(null, { view: this }); }, events: { "click #check": "checkIn" }, checkIn: function() { var world_name = prompt("请问你是哪里人"); if (world_name == "") world_name = "未知"; var world = new listView.World({ name: world_name }); this.worlds.add(world); }, addOneWord: function (model) { $("#world-list").append("<li>我是来自:" + model.get("name") + "的人!</li>"); } }) }; return listView; });
然后在require_config.js的path中进行定义,例如:
(function () { var baseurl = "/Scripts/"; require.config({ paths: { "index":baseurl+"lib/index" }, }); })();
之后再在页面对这个index模块进行加载,如:
require([‘index‘], function(indexView) { var app = indexView.AppView; var AppView = new app; });
Define和require在依赖处理和回调执行上是一样的,但是define回调的函数需要有return语句返回模块对象,这样define定义的模块才能被其他模块调用;require回调函数不需要有return语句。
所以说define和require都可应用来加载和使用模块,但是define可以用来定义模块,用define定义的模块必须要有返回值