javascript模块技术是让javascript这门语言通往工程化和编写大型应用的一块敲门砖,因为它彻底解决了js文件依赖混乱和全局变量污染的问题。
什么是依赖混乱?
例1:现在几十个js文件:
// f1.js
var f1 = function(){
// active code
}
// f2.js
var f2 = function(){
// active code
}
....省略几十个
当在html文件引入几个js文件的时候,如果他们之间的依赖关系是这样的,f1依赖f2和f3,f3依赖f4和f5,f5依赖f1和f6...(省略几十个文件依赖)。在如此复杂和混乱依赖情况,如果要捋清楚几十个js文件的引入顺序的话,是非常困难和烦人的。
什么是全局变量污染?
例2:现在有三个js文件:
// a.js
var myName = 1
// b.js
var myName = 2
// c.js
var myName = function(){}
当html文件依次引入a,b,c三个js文件后,打印myName变量,会发现c.js中的myName变量把 a.js 和 b.js的myName变量覆盖了。在实际的开发中,引入多个js文件很容易造成变量覆盖问题,这个问题的后果是很严重的。
ES6和commonJS的出现
2008年,goole浏览器的v8引擎发布之后呢,出现了Node,javascript这门语言被应用到了后端,既然作为一个后端语言,连一个模块化的技术都没有,是无法流行和壮大发展起来的,因为当时的java ,c++这些语言的模块化技术已经很成熟了,对比这些主流的后端语言Node没有任何优势。因此,为了Node发展,javascript语言的模块化技术是迫不及待要实现的。于是社区就开始了讨论各种实现模块化的方法,最后commonJS也就诞生了,因此Node也应用了commonJS的标准和理念来实现模块化。
Node实现了模块化技术,浏览器端的模块化技术也开始发展,最后AMD和CMD技术出现了。模块化技术是有了,但是commonJS和AMD和CMD都是属于社区讨论出来的方案。直到ES6的发布,ECMA官方才正式发布ES6模块化标准。总结为:commonJS只适用于Node,而ES6模块化支持Node和浏览器端。
模块化技术如何解决依赖混乱和全局变量污染问题?
利用导入和导出的功能,在js文件内部就清晰捋清楚了文件之间的依赖关系,明确需要引入什么模块,最后只需要引入一个入口的js文件即可,不需要再困扰在.html文件引入js文件的顺序的问题这样就彻底解决了依赖混乱的问题。
模块的内部在运行之前,先把整份代码拿到立即执行函数里面运行一遍,因此保证了,所有的变量都是局部变量,避免了js文件之间的全局变量污染的问题。
ES6和commonJS的语法对比
只列举常用的导入导出方式
-------------------------------------
ES6:
// 导出模块
// a.js
方式一:
export const a = 1
方式二:
const b = 2
export { b }
export default 3
//浏览器端的ES6导入需要在index.html文件引入script标签,并标志type值为module
<script src='./a.js' type='module'></script>
// 引入模块
// b.js
方式一:import c ,{ a , b } from './a.js'
方式二:import { default as c , a ,b } from './a.js'
--------------------------------------
commonJS:
// 导出模块
// a.js
方式一:exports.a = 1
方式二:module.exports = {a:1,b:2}
//引入模块
const obj = require('./a.js') // {a:1,b:2}
ES6和commonJS的一些区别
从语法的角度上看,ES6模块化的import 和 export 是一个内置的标识,而commonJS的module.exports 和 require 分别是js对象和方法。其ES6模块化和commonJS的实现方式不同。
1.ES6是在编译的时候导入文件,而commonJS是编译完成后,在通过require方法导入,并读取文件导出的文件,并返回一个module.exports对象
2.在ES6模块的内部this是问undefined,而commonJS的this为一个空对象
3.ES6模块输出的是一个引用,而commonJS模块输出的是一个值的引用
//commonJS
//a.js
let a = 1
function count(){
a ++
}
module.exports = {
a,
count,
}
//b.js
let obj = require('./a.js')
obj.count()
console.log(a) //1
//ES6模块
//a.js
let a = 1
function count(){
a++
}
export { a , count }
//b.js
import { a ,count } from './a.js'
count()
console.log(a) //2