这三个规范有什么用:
这三个规范可以帮助你加载各个模块,完成各个模块的作用域独立
那么模块是什么,作用域又是什么?
1、作用域:
作用域指在一个区域内有效的区域。
熟悉javascript的应该知道,javascript是函数级作用域,在函数内可以访问到函数外的变量,而函数外不能访问到函数内的变量,这个就是函数的作用域。
在函数外的变量会变成全局变量。一个比较大的项目需要很多变量命名,很容易就会造成命名冲突。那么该怎么解决呢,我们知道函数内的变量是不被外部访问的,自然也不会造成对命名冲突。那么该怎么使用函数去进行避免命名冲突呢?下面引入我们的模块:
2、模块:
模块具有对外可见,外部不可修改,作用域独立的效果。那么什么是模块呢?
个人理解为一个立即执行的函数,可以是一个匿名函数,并且立即执行。
(function(){
var name = "张三";
console.log(name) // 张三
})()
console.log(name) // undefined
这样可以成为一个模块,函数内部可以访问到变量,外部则访问不到。不过一般一个标准的模块应该这么用:
var user = (function(){
var name = "张三";
// 获取名字
function getName(){
return name;
}
// 修改名字的方法
function setName(name){
name = name;
}
// 向外提供的方法
return {
getName:getName,
setName:setName,
}
})()
console.log(user.getName()) // 张三
user.setName("李四")
console.log(user.getName()) // 李四
这样是不是就可以做到作用域独立,对外提供我想要提供的方法。实现了获取名字,修改的名字的功能。并且不会造成环境的变量污染。
commonJs规范:
下面看一个小例子:
创建一个index.js文件:
// index.js
var name = "张旭伟"
在创建一个 index2.js文件:
// index2.js
console.log(name)
创建一个html文件将他们一起引入:
<script type="text/javascript" src="index.js"></script>
<script type="text/javascript" src="index2.js"></script>
执行html文件将会打印出 index.js中定义的变量name。
可以知道在一个html文件中一起引入的 js文件之间是可以互相访问到全局变量的,这显然不符合我们的作用域互相独立的规则。
我们可以使用模块的方式,对各自js文件进行隔离。
// index.js
(function(){
var name = "张旭伟"
})()
// index2.js
(function(){
console.log(name)
})()
这样就已经做到了文件之间互相隔离。
commonJS的规范就是每一个文件为一个模块,作用域独立,互相不受影响。
commonJs认为每一个文件为一个模块,通过module.exports输出模块内容,每个模块当前对象都是module,导出的对象为module下的属性exports。通过require命令引入。
下面实践,创建项目结构如下:
module1.js 、module2.js为模块,app.js为入口文件(执行入口)
module1.js
// module1.js
module.exports = function () {
var name = "这是module1模块";
console.log("我是module1模块");
function getName() {
return name;
}
return {
getName:getName,
};
}
module2.js
// module2.js
module.exports = function () {
var name = "这是module2模块";
console.log("我是module2模块");
function getName() {
return name;
}
return {
getName:getName,
};
}
app.js
// app.js
var module1 = require("./modules/module1.js")
var module2 = require("./modules/module2.js")
console.log(module1().getName())
console.log(module2().getName())
运行app.js
node app.js
得到输出结果,没有问题,这就是commonJs规范。
但是这只适合在服务器上使用。
因此,有了下面的AMD规范。
AMD规范
AMD规范是为浏览器上运行而推出的,同样也是为了使文件模块化。
AMD规范需要借助require.js去实现
require.js可以帮助我们实现AMD规范,并且将多个文件作为一个在html中共同引入。
1、下载require.js
2、新建一个主文件main.js,并进行如下配置:
// 配置文件
requirejs.config({
baseURI:'js/', // 加载模块的根路径
paths:{ // 模块映射,映射需要使用的模块
"index1":"js/index",
"index2":"js/index2"
}
})
requirejs(["index1","index2"],function (index, index2) {
})
3、define定义模块:
index.js:
define(function () {
var str = "这是index.js的数据"
return "这是index.js模块"
})
index2.js:
define(['./module1.js'],function (module1) { // 此处加载依赖文件
var str = "这是index2.js的数据"
return "这是index2.js模块"
})
可以给定义模块返回值。
4、html中引入require.js:
<script data-main="main.js" src="require.js"></script>
data-main: 属性为require.js的配置文件路径,用于找打配置文件。
src: 引入require.js文件。
5、执行html文件,可以看到已经把index.js,index.js也都引入了。并且作用域互补影响。
有时候我们还会需要引入第三方插件、库,也可以当做一个模块进行引入。但是有的插件、库没有模块化呢?怎么办。
可以使用require.js中的shim模块,配置如下:
// 配置文件
requirejs.config({
baseURI:'js/', // 加载模块的根路径
paths:{ // 模块映射
"index1":"js/index",
"index2":"js/index2"
},
shim:{
"index2":{ // 需要模块化的文件
deps:[], // 该插件需要依赖的文件
exports:"index2" // 输出名称
}
}
})
requirejs(["index1","index2"],function (index, index2) {
console.log(index)
console.log(index2)
})
CMD规范
CMD规范是commonJS和AMD规范的合体,取自两者的一半,进行修改,成为CMD规范。
CMD规范需要借助sea.js实现。
下面为项目结构。
1、下载sea.js
2、定义模块(文件模块化)
module1.js
// module1.js
define(function (require, exports, module) {
console.log("我是module1模块");
module.exports = '这是module1模块';
});
module2.js
define(function (require, exports, module) {
// let module1 = require("./module1.modules"); // 同步加载依赖文件
require.async("./module1.modules",function (module1) { // 异步加载文件
// 加载完后执行回调
console.log(module1) // 打印module1的输出内容
});
console.log("我是module2模块");
module.exports = "这是module2模块"; // 输出自己
});
3、入口文件(执行入口):app.js
define(function (require, exports, module) {
var module2 = require("./modules/module2.js")
console.log(module2)
});
4、HTML中引入
引入sea.js
<script type="text/javascript" src="lib/sea.js"></script>
加载入口文件:
<script>
seajs.use("./app.js")
</script>
5、执行html文件:
browserify
commonJS规范初衷是为服务器端的文件进行模块化。其实commonJs的规范也可以在浏览器上运行,不过需要使用browserify工具去编译。
1、安装 browserify
全局安装
npm install -g browserify
局部安装
npm install --save-dev browserify
2、编译
使用browserify编译main.js文件(入口文件)
browserify main.js -o build.js
这个操作是将main.js配置里面引入的模块一起打包为一个文件,并且命名为build.js
3、html中使用
html中引入build.js,执行html可以得到服务器上运行同样的效果
ES6模块化:
javascript吸收了第三方模块化规范的精神,es6开始加入模块化,无需使用第三方规范即可使用模块化。
1、es6暴露模块方式:
第一种:多个对象单独暴露
export function show() {
console.log('这是module1模块')
}
export function show2() {
console.log('这是module1模块')
}
第二种:默认暴露(多个对象统一暴露)
function show() {
console.log('这是module1模块')
}
function show2() {
console.log('这是module1模块')
}
export default{
show,
show2
}
2、引入模块:
第一种:按变量方式引入(解构赋值方式),针对单独暴露
import {show,show2} from "module"
第二种:按模块方式引入,针对统一暴露
import module from "module"
3、浏览器上使用
需要先对模块进行编译
编译可使用browserify工具编译(对入口文件编译即可),browswerify的使用前面有讲到。
在使用browserify编译之前呢,有一个问题,它不认的es6语法,需要对编译的文件进行转换为es5语法,然后再进行编译。
编译完成后即可引入浏览器使用。
了解es6转换为es5可移步:使用 babel 将 ES6 转换为 ES5