JavaScript中全部对象的属性都是公共的,并无什么明确的方法来代表属性可否从对象的外部被访问,而有时候咱们并不但愿对象的属性被外界访问。一种方式方式经过命名约定的形式,好比在变量的前面加下划线(_)。还有一些其余的方式是属性彻底私有化。javascript
在模块化没有出现以前,咱们JavaScript脚本大概是这样的:html
<script src="module1.js"></script> <script src="module2.js"></script> <script src="module3.js"></script> <script src="module4.js"></script> ....
但咱们引入多个js文件时,会存在一些问题:前端
script
就会变得不少,而且难以维护。为了解决这些问题,涌现了各类模块化的方案。java
这种方式是建立对象的一种方法,用于建立具备私有属性的对象。基本思路是使用一个当即执行的函数表达式,返回一个对象。该函数表达式能够包含任意数量的局部变量,这些变量从函数的外部是没法访问到的。由于返回的对象是在自执行函数内部声明的,因此对象中定义的方法能够访问自执行函数内的局部变量,这些方法被具备特权的方法。node
var p2 = (function(){
var money = 30000;
return {
name: 'lisi',
sayMoney: function(){
return money;
}
};
}());
咱们在前端的js代码在没有模块化以前也能正常执行,可是在服务器端的js脚本必需要被模块化才能正常工做。因此虽然JavaScript在前端发展了这么多年,第一个流行的模块化规范倒是由服务器端的js应用发展起来的。CommonJS规范是由NodeJS发扬光大的。数组
在CommonJS规范中,一个单独的JS文件就是一个模块。每一个模块都是一个单独的做用域,也就是说,在该模块内部定义的变量,没法被其余模块读取,除非定义为global对象的属性。浏览器
模块只有一个出口,module.exports
对象,咱们须要把须要输出的内容放入该模块服务器
加载模块使用require()
方法,该方法读取一个文件并执行,返回文件内部的module.exprots
对象异步
例如,咱们写了这样一个文件myModule1.js
:模块化
var name = '无忌';
function sayName(){
console.log(name);
};
function sayFullName(firstName){
console.log(firstName + name);
};
module.exports = {
printName:sayName,
printFullName:sayFullName
};
咱们的模块定义好了,那咱们怎样使用这个模块呢?例如,咱们建立了myModule2.js
文件:
var module1 = require('./myModule1.js');
module1.printName();
module1.printFullName('张');
在node环境下,require方法在引入其余模块的时候是同步的,能够轻松的控制模块的引入顺序,保证了模块之间的依赖顺序。可是在浏览器中却不是这样的,由于咱们的<script>
标签天生异步,在加载js文件的时候是异步的,也就意味着不能保证模块之间的正确依赖。
AMD即Asynchronous Module Definition,异步模块定义。它是在浏览器端实现模块化开发的规范。因为该规范不是JavaScript原始支持的,使用AMD规范进行开发的时候须要引入第三方的库函数,也就是鼎鼎大名的RequireJS
。
RequireJS主要解决两个问题:
js加载的时候浏览器会中止页面渲染,加载的文件越多,页面失去响应的时间越长。
定义模块
RequireJS定义了一个define
函数,用来定模块。
define(id, [dependencies], factory);
// amdModule1.js
define('amdModule1',[],function(){
console.log('模块一');
var name= '张三';
var money = 1000;
var sayName = function(){
return name;
}
var sayMoney = function(){
return money;
}
return {
sayName:sayName,
sayMoney:sayMoney
}
})
// module2.js
define('amdModule2',['amdModule1'],function(amdModule1){
console.log('模块二');
var name = '李四';
var weight = 80;
var sayName = function(){
return amdModule1.sayName();
}
var sayWeight = function(){
return weight;
}
return {
sayWeight:sayWeight,
name:name,
sayName:sayName
};
})
加载模块须要使用require()
函数。
require([dependencies], function(){});
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <script src="require.js"></script> <script type="text/javascript" src="amdModule1.js"></script> <script type="text/javascript" src="amdModule2.js"></script> <script type="text/javascript"> require(['amdModule1','amdModule2'],function(amdModule1,amdModule2){ console.log(amdModule1.sayName()); //张三 console.log(amdModule1.name); //undefined console.log(amdModule2.sayName()); //张三 console.log(amdModule2.sayWeight()); //80 }); </script> </body> </html>
require()
函数在加载依赖的模块时,是异步加载的,这样浏览器就不会失去响应,回调函数只有在所依赖的所有模块都被被成功加载以后才执行,所以,解决了依赖性的问题。
CMD即Common Module Definition通用模块定义。它解决的问题和AMD规范是同样的,只不过在模块定义方式和模块加载时机上不一样。CMD也须要额外的引入第三方的库文件,SeaJS。
SeaJS推崇一个模块一个文件,遵循统一的写法:
define(id, dependencies, factory);
由于CMD推崇一个文件一个模块,因此常用文件名做为模块的ID;CMD推崇就近原则,因此通常再也不define的参数中写依赖,在factory函数中写。
// cmdModule1.js
define(function(require,exports,module){
var name = '张三';
function sayName(){
return name;
}
module.exports={
sayName:sayName
}
})
// cmdModule2.js
define(function(require,exports,module){
var cmdModule1 = require('cmdModule1.js');
console.log('模块');
function sayName(){
return cmdModule1.sayName();
}
module.exports={
sayName:sayName
}
})
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <script src="sea.js"></script> <script src="cmdModule2.js"></script> <script src="cmdModule1.js"></script> <script type="text/javascript"> seajs.use(['cmdModule2.js','cmdModule1.js'],function(cmdModule2,cmdModule1){ console.log(cmdModule2.sayName()); console.log(cmdModule1.sayName()); }) </script> </body> </html>
AMD在加载模块完成后会当即执行该模块,全部的模块都加载完成后执行require
方法中的回调函数,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不必定一致,看网速,谁先下载下来,谁先执行,可是咱们的主逻辑必定是在全部的依赖模块都被加载完成后才执行。
CMD加载完某个模块的时候并不执行,只是把它们下载下来而已,在全部的模块下载完成后,当使用require
请求某个模块的时候,才执行对应的模块。