作为刚刚入门前段的小白,前不久刚刚接触了js模块化的概念,从该开始写代码时的各种全局变量飞,到现在的封装模块,感觉又上了那么一个台阶了,不再那么业余了。接下来就总结一下最近的学习心得。
js模块化
- 没有模块化的时候
function f1(){}
function f2(){}
缺点:会污染全局变量
- 将变量封装在对象内
var obj1 = {
f1:function (){},
f2:function (){}
}
缺点:对象的属性直接暴露在外面,可以被随意修改,封装性不好
- 使用立即执行函数
var module1 = (function(){
function f1(){}
function f2(){}
return {
f1:f1,
f2:f2
}
})()
module1.f1()
module1.f2()
这样写的好处在于,使用者不能修改模块内部规定好的变量和函数。
- 模块化标准
js模块化主要有两种规范:CommonJS和AMD
- CommonJS应用于服务器端(nodejs环境下)
- AMD规范应用于浏览器端(浏览器环境)
- 注:CommonJS采用同步加载模块策略,服务器端js文件都放在硬盘上可以同步读取;AMD全称"asynchronous module definition",异步模块定义,浏览器请求js文件是异步的,这也是浏览器不能使用CommonJS加载模块的原因。
AMD规范举例
引用模块
require(["math"],function(math){
math.add();
});
其中math模块的加载和math.add()方法调用不是同步的,而是等待math模块请求到之后才会调用math方法。
关于同步异步的知识可以参考阮一峰的js教程的单线程模式
RequireJS库
使用requirejs的原因
最早由于网页功能没有那么复杂,所有js代码都放在一个文件内,随着功能的不断增强,js代码需要分模块编写,于是分成不同的文件存放不同的模块。
<script src="1.js"></script>
<script src="2.js"></script>
<script src="3.js"></script>
上面写法的缺点:
- 依赖必须按照依赖顺序写,依赖性越强的js代码要放在下面,比如3.js依赖1.js的话,3.js就必须放在1.js下面,一旦文件多了,依赖关系复杂,就不太容易处理了;
- 分文件存放模块,会产生很多网络请求,网络请求越多网页失去响应的时间就会越长。
requirejs产生就是为了解决上述两个问题。
requirejs使用方法
- 网页中只有一个script标签,如下
<script data-main="js/main.js" src="js/reqire.js"></script>
data-main属性内存放js的入口文件;
src属性存放require.js文件的路径。 - 主模块写法
//main.js
requirejs.config({
baseUrl:"",
paths:{
}
});
require(["jquery","event"],function($,event){
});
包含两部分:配置和自定义代码。
配置:使用requirejs.config()方法,参数是一个对象。baseUrl属性可以指定一个默认地址,然后模块的地址就可以以这个默认地址作为参考系来设置了;paths属性可以再相对于baseUrl属性设置更多的绝对路径。这样做的目的是为了避免路径较深时,写很多长路径名。
例如:文件路径如下
- www
- index.html
- js
- app
- gotop.js
- lib
- jquery.js
- app
如果不设置baseUrl,我们使用模块时,必须向下面这么用
require(["js/app/gotop",js/lib/jquery])
使用baseUrl+paths:
require.config({
baseUrl:"js",
paths{
lib:"lib",
app:"app"
}
})
require(["app/gotop","lib/jquery"])
注:如果模块名符合下述三种条件之一则不使用baseUrl+paths的方式寻找模块,而是直接从加载require.js文件的html文件的所在目录开始寻找模块。
- 以".js"结束
- 以"/"开始
- 包含URL协议,如"http","https"
3.定义一个模块
//select.js
define(["lib/jquery"],function($){
function sel(selecor){
return $(selector)
}
return {
sel:sel
}
})
define定义了一个select模块,第一个参数是select模块所依赖的模块,第二个参数是回调函数,当jquery模块加载完成后,开始执行select模块的定义。
如果另一个模块需要使用select模块,需要按下面方法加载:
//main.js
require(["select"],function(select){
var tab = select.sel(".tab");
})
4.r.js的使用
我们使用以上方法将一个一个模块按规范书写后,就不再需要考虑掉用他们的时候先引用谁后引用谁了,这个工作已经由requirejs帮我们完成了。但是这只解决了引用顺序的问题,仍然会产生很多的网络请求,这时候就轮到r.js登场了,它可以帮我们把之前定义好的模块都打包压缩到一个文件内。
安装requirejs:
npm install -g requirejs
以下面的例子为例:
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
<link rel="stylesheet" type="text/css" href="css/main.css">
<script data-main="scripts/main.js" src="scripts/require.js"></script>
</head>
<body>
<h1>My App</h1>
</body>
</html>
- myproject
- index.html
- scripts
- require.js
- main.js
- one.js
- two.js
- three.js
main.js是入口文件,依赖于one,two,three。
//main.js
require.config({
baseUrl:"scripts"
})
首先我们要在index.html所在路径新建一个build.js,用于存放r.js所需要的配置文件。
//build.js
({
baseUrl:"script",//这个路径是相对于build.js文件所在路径的,不是index.html
paths:{
//也可以根据需要添加
},
name:"main",//入口文件
out:"merge.js"//输出文件的路径及文件名称,路径不是相对于baseUrl的,而是相对于build.js所在路径的
})
新建好build.js后,在命令行切换至build.js所在目录,执行如下命令
r.js -o build.js
生成mergr.js后,我们还要修改html中script标签的data-main属性
<script data-main="merge.js" src="require.js"></script>
此时,整个html页面就只有一条两条html请求了,即merge.js和require.js。
网友评论