一、无模块化的时代
1.命名的冲突
2.文件依赖
二、初步解决无模块化的bug
1.全局函数
就是将重复的代码放在函数中,再将一系列函数放在一个js文件中,这个文件中的所有函数就是一个特定功能的实现,这个文件就是一个模块
缺点 :污染全局变量,模块成员之间看不出直接关系。
2.对象命名空间
形式上解决了命名冲突问题,但并不能从根本上解决
缺点:内部状态可被外部改写。
3.私有公有成员分离 ,
就是执行函数,私有的变量和函数不会影响到全局作用域
虽然解决了变量命名冲突的问题
(function(root){
// 私有
var num=1;
// 公有
root.run=function(){
console.log(num);
}
})(this);
总之,以上三个方法并没有解决开发复杂度的问题。
三、Common.JS 模块化时代
1.服务器端(如node.js)使用Common.js, 它是同步的
//foo.js文件
var x = 5;
var addX = function (value) {
return value + x;
};
// 三种方式导出接口
module.exports.x = x;
module.exports.addX = addX;
// exports.x=x;
// exports.addX=addX;
// module.exports={
// x:x,
// addX:addX
// }
// 而这个导出接口不对
// module.exports = x;
// module.exports = addX;
//nodeTest.js文件
var example = require('./foo.js');
console.log(example.x); // 5
console.log(example.addX(1)); // 6
2.CommonJS模块的特点:
所有代码都运行在模块作用域,不会污染全局作用域。
模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
模块加载的顺序,按照其在代码中出现的顺序。
一个模块就是一个文件,一个模块就是module对象,这个module对象就是node内部的Module构造函数new出来的实例。
module.exports属性表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取module.exports变量。
3.CommonJS规范和AMD规范的区别
CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。
AMD规范则是异步加载模块,允许指定回调函数。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用异步模式,因此浏览器端一般采用AMD规范。
4.CommonJS模块的加载机制
是:输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
四、Require.js模块化时代( AMD)
1. 浏览器端使用Require.js, 它异步的
2.AMD是异步模块定义,它采用异步方式加载模块,通过define方法去定义模块,require方法去加载模块
define([依赖的模块1,依赖的模块1],function(){
})
require([加载的模块1,加载的模块1],function(){
//require参数一异步加载模块1.模块2成功后才会执行require参数二回调函数,这样浏览器不会失去响应,解决了依赖性问题
}
//b.js 文件
define(function(){
var name='xtt';
return {
name:name
}
})
// a.js文件
define(['b'],function(b){
console.log(b); //{name:"xtt"}
var Hello=function(){
console.log('hello world');
}
return { //接口对象
Hello:Hello
}
//这两者不可以导出接口对象
// module.exports={Hello:Hello};
// exports.Hello=Hello;
})
//test.html
<script src="./require.js"></script>
<script>
require(['a', 'b'], function (a, b) {
console.log(a);
console.log(b);
})
</script>
五、Sea.js模块化时代(CMD)
1. 浏览器端使用Sea.js, 它异步的
2.CMD 即通用模板定义,CMD规范是国内发展起来的;
define(function(require,exports,module){
// 模块代码
//require:是可以把其他模块导入进来的一个参数;
//exports:可以把模块内的一些属性和方法导出;
//module是一个对象,上面存储了与当前模块相关联的一些属性和方法
CMD推崇依赖就近,延迟执行。文件是提前加载好的,只有在require的时候才去执行文件
})
//b.js文件
define(function(require,exports,module){
exports.max='xtt';
});
//a.js文件
define(function(require,exports,module){
var b=require('b');
console.log(b);
// 下面三种方式均可以导出接口
exports.Hello=function(){
console.log('hello work');
}
// module.exports={
// Hello:function(){
// console.log('hello work');
// }
// }
// return {
// Hello:function(){
// console.log('hello work');
// }
// }
});
//test.html文件
<script src="./sea.js"></script>
<script>
// 配置
seajs.config({
alias:{
'a':'./a',
'b':'./b'
}
});
// 启动模块加载器
seajs.use(['a','b'],function(a,b){
console.log(a);
console.log(b);
});
</script>
六、ES6 module模块化时代(重点)
1.export用于把模块里的内容暴露出去
2.import用于引入模块提供的功能
3.可以使用export default命令,为模块指定默认输出,一个模块只能有一个默认输出,所以export default只能使用一次
❤详细如何导入导出(import/export)查看此篇文章
4.ES6模块是动态引用,如果使用import从一个模块加载变量(即 import foo from 'foo'),变量不会被缓存,而是成为一个指向被加载模块的引用。等脚本执行时,根据只读引用,到被加载的那个模块中去取值。
5.ES6支持浏览器端也支持node端