模块化
模块化是什么?
含义:将一个复杂的程序依据一定的规则(规范)封装成几个块(文件),并进行组合在一起的内部数据/实现是私有的,只是想外部暴露一些接口(方法)与外部的模块通信
进化史
<script type="text/javascript">
let msg='module1'
function foo()
{consloe.log('foo()',msg)}
</script>
<script type="text/javascript">
foo();
msg='change';
foo();
</script>
Global被污染,很容易命名冲突
<script type="text/javascript">
let obj={
msg:'module2'
foo(){
consloe.log('foo()',msg)}
</script>
<script type="text/javascript">
obj.foo();
obj.msg='change';
obj.foo();
</script>
减少Global上的变量数目,本质是对象,并不安全
<script type="text/javascript">
(function(window){
let msg='module3';
function foo(){
console.log('foo()',msg)
}
window.module3={
foo:foo}
})(window)
</script>
<script type="text/javascript">
module3.foo()
</script>
<script type="text/javascript">
(function(window,$){
let msg='module4';
function foo(){
console.log('foo()',this.msg)
}
window.module4=foo;
$('body').css('background','red')
})(window,JQuery)
</script>
为什么要模块化?
- web 的发展飞速,不仅仅局限于静态页面,而向着应用发展,功能越来越丰富
- 代码复杂度越来越高
- 对代码进行解耦的需要
- 减少文件大小,节约 Http 请求时间
模块化的好处
- 避免命名冲突(减少命名空间污染)
- 更好的分离,按需加载
- 更高复用性
- 高可复用性
实现方式
页面引入<script> 加载资源 进而引发的问题
模块化规范
commonjs
规范
- 每个文件都可当做一个模块
- 在服务器:模块的加载是运行时同步加载的
- 在浏览器:模块需要提前编译打包处理
基本语法
- 暴露模块
module.exports = value(任意数据类型) exports.xxx = value - 引入模块
require(xxx) 第三方模块:xxx 为模块名 自定义模块:xxx 为模块文件路径
实现
- 服务器端实现
Node.js nodejs.cn/
1.下载node.js
2.创建项目结构
/-modules
/-module1.js
/-module2.js
/-module3.js
/-app.js
/packpage.json{
"name":"commonJS-node"
"version":"1.0.0"}
//npm init
3.下载第三方模块
npm install uniq
在npm官网搜索uniq
4.模块化编码
module1.js......
//使用指令node app.js运行
module1.js
//module.exports=value 暴露一个对象出去
module.exports={
msg:'module1',
foo(){
console.log(this.msg)
}
}
module2.js
//暴露一个函数 module.exports=function(){}
module.exports=function(){
console.log('module2') ;
}
module3.js
exports.foo=function(){
console.log('foo() module3');
};
exports.bar=function(){
console.log('bar() module3');
}
exports.arr=[2,4,5,2,3,5];
app.js
let module2=require('./modules/module2');
let module3=require('./modules/module3');
module1.foo();
module2();
module3.foo()
module3.bar()
let result=uniq(module3.arr);
console.log(result);
- 浏览器端实现
Browserify 称为 CommonJS 的浏览器端的打包工具 browserify.org/
1.创建项目结构
/-js
/-dist//打包生成文件的目录
/-src//源码所在的目录
/-module1.js
/-module2.js
/-module3.js
/-index.html
/-package.json
2.下载browserify
*全局:npm install browserify -g
*局部:npm install browserify --save-dev
3.定义模块代码
*module1.js
4.打包处理js
browserify js/src/app.js -o js/dist/bundle.js
app.js
let module1=require('./module1');
let module2=require('./module2');
let module3=require('./module3');
module1.foo();
module2();
module3.foo()
module3.bar()
bundle.js
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
let module1=require('./module1');
let module2=require('./module2');
let module3=require('./module3');
module1.foo();
module2();
module3.foo()
module3.bar()
},{"./module1":2,"./module2":3,"./module3":4}],2:[function(require,module,exports){
module.exports={
msg:'module1',
foo(){
console.log(this.msg)
}
}
},{}],3:[function(require,module,exports){
module.exports=function(){
console.log('module2') ;
}
},{}],4:[function(require,module,exports){
exports.foo=function(){
console.log('foo() module3');
};
exports.bar=function(){
console.log('bar() module3');
}
exports.arr=[2,4,5,2,3,5];
},{}]},{},[1]);
AMD
说明
语法
定义暴露模块
define(function(){
return 模块
})
define(['module1', 'module2'], function(m1, m2) {
return 模块
})
引入使用模块
require(['module1', 'module2'], function (m1, m2) {
使用 m1/m2
})
实现(浏览器)+require.js使用教程
官网:http://www.requirejs.cn/
github : https://github.com/requirejs/requirejs
将require.js导入项目:js/libs/require.js
2.创建项目结构
alerter.js
define(['dataservice','jquery'],function(dataservice,$){
let msg='alerter.js';
function showMsg(){
console.log(msg,dataservice.getName());
}
$('body').css('background','red')
return {showMsg}
})
dataservice.js
define(function(){
let name='dataservice.js';
function getName(){
return name;
}
return {getName};
})
main.js
(function(){
requirejs.config({
baseUrl:'js/',
paths: {
dataservice:'./modules/dataservice',
alerter:'./modules/alerter',
jquery:'./libs/jquery'
}
});
requirejs(['alerter'],function(alerter){
alerter.showMsg();
})
})();
html
<body>
<script data-main="js/main.js" src="js/libs/require.js"></script>
</body>
CMD
说明
- Common Module Definition (通用模块定义)
- 专门用于浏览器端,模块的加载是异步的
- 模块使用时才会加载执行
基本语法
define(function(require, exports, module) {
exports.xxx = value
// or
module.exports = value
})
定义有依赖的模块
define(function(require, exports, module) {
// 引入依赖模块(同步语法)
var module2 = require('./module2')
// 引入依赖模块(异步)
require.async('./module3', function() {
// 暴露模块
exports.xxx = value
})
})
define(function(require) {
var m1 = require('./module1')
var m4 = require('./module4')
m1.show()
m4.show()
})
实现(浏览器端)
Sea.js
seajs.github.io/seajs/docs/
requireJS
说明
RequireJS 是一个JavaScript模块加载器。 在ES6出现之前,JS不像其他语言同样拥有“模块”这一概念,于是为了支持JS模块化,出现了各种各样的语言工具,如webpack,如ReuqireJS。
为什么使用
- 模块化:模块化就是将不同功能的函数封装起来,并提供使用接口,他们彼此之间互不影响。
- 不会阻塞页面:RequireJS,会在相关的js加载后执行回调函数,这个过程是异步的,所以它不会阻塞页面。
- 按需加载:平时我们写html文件的时候,在底部可能会引用一堆js文件。在页面加载的时候,这些js也会全部加载。使用require.js就能避免此问题。举个例子,比如说我写了一个点击事件,放到了一个js文件里,并在html引用,在不使用require.js的情况下,页面加载它跟着加载,使用后则是什么时候触发点击事件,什么时候才会加载js。
使用
- 在html引入require.js
require.js可以npm下载,或者去官网下载。 script里有个data-main属性,require.js会在加载完成以后通过回调方法去加载这data-main里面的js文件,所以这个js文件被加载的时候,RequireJS已经加载执行完毕。
<script type="text/javascript" data-main="js/main.js" src="js/libs/require.js"></script>
- 配置main.js
require()函数接受两个参数。第一个参数是一个数组,表示所依赖的模块,上例就是[‘moduleA’, ‘moduleB’, ‘moduleC’],即主模块依赖这三个模块;第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。 require()异步加载moduleA,moduleB和moduleC,浏览器不会失去响应;它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。
//main.js
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
// some code here
});
使用require.config()方法,我们可以对模块的加载行为进行自定义。require.config()就写在主模块(main.js)的头部。参数就是一个对象,这个对象的paths属性指定各个模块的加载路径。
//main.js头部配置
require.config({
baseUrl: "js/lib",
paths: {
"jquery": "jquery.min",
"underscore": "underscore.min",
"backbone": "backbone.min"
}
});
在main.js里引入jquery
require.config({
paths:{
"jquery":'../lib/jquery.min'
}
});
require(['jquery'],function($){
...
//通过此方式引入jquery才能使用$,接下来正常写jquery代码就好
})
- eg:自己编写的模块不像第三方插件可以直接引用,要引用自己写的模块,首先要对模块进行定义。
如下面的例子,命名为mtWindow.js,也在script目录下
define(function(){
var mtWindow=function(msg){
$(".body_contanier").append('<div class="modai"><div class="motai_up"><p class="attention">提示</p><p class="charcter">'+msg+'</p></div><span class="mt_line"></span><p class="motai_down">确定</p></div><div class="overlay"></div>');
$(".modai").css("display","block")
.next().css("display","block");
$(".motai_down").click(function(){
$(".modai").css("display","none")
.next().css("display","none");
$(".modai").remove();
$(".overlay").remove();
});
}
return {
mtWindow:mtWindow
};
})
注意,此模块也用到了$,因此在main.js里引用此模块的时候,需要嵌套引用。
require(['jquery'],function($){
require(['mtWindow'],function(mtWindow){
mtWindow.mtWindow("手机号格式错误");
})
})
JavaScript 代码规范
- 变量名
变量和函数为小驼峰法标识, 即除第一个单词之外,其他单词首字母大写( lowerCamelCase) 全局变量为大写 (UPPERCASE ) 常量 (如 PI) 为大写 (UPPERCASE )
HTML 和 CSS 的横杠(-)字符:
HTML5 属性可以以 data- (如:data-quantity, data-price) 作为前缀。
CSS 使用 - 来连接属性名 (font-size)。
- 空格与运算符
通常运算符 ( = + - * / ) 前后需要添加空格 - 代码缩进
通常使用 4 个空格符号来缩进代码块:
function toCelsius(fahrenheit) {
return (5 / 9) * (fahrenheit - 32);
}
- 语句规则
1.一条语句通常以分号作为结束符。
2.复杂语句的通用规则:
将左花括号放在第一行的结尾。
左花括号前添加一空格。
将右花括号独立放在一行。
不要以分号结束一个复杂的声明。
var values = ["Volvo", "Saab", "Fiat"];
var person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};
- 对象规则
对象定义的规则: 将左花括号与类名放在同一行。 冒号与属性值间有个空格。 字符串使用双引号,数字不需要。 最后一个属性-值对后面不要添加逗号。 将右花括号独立放在一行,并以分号作为结束符号。
var person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};
- 使用小写文件名
参考:JavaScript模块化历程 参考:尚硅谷commonjs网课 参考:RequireJs入门
|