function fun1(){
//...
}
function fun2(){
//...
}
//上面的函数fun1,fun2组成了一个模块,使用的时候直接调用某个函数就行了。
var module1 = new Object({
count : 0,
fun1 : function (){
//...
},
fun2 : function (){
//...
}
});
//这个里面的fun1和fun2都封装在一个赌侠宁里,可以通过对象.方法的形式进行调用;
module1.fun1();
var module1 = (function(){
var count = 0;
var fun1 = function(){
//...
}
var fun2 = function(){
//...
}
//将想要暴露的内容放置到一个对象中,通过return返回到全局作用域。
return{
fun1:fun1,
fun2:fun2
}
})()
//这样的话只能在全局作用域中读到fun1和fun2,但是读不到变量count,也修改不了了。
//问题:当前这个模块依赖另一个模块怎么办?
var module1 = (function (mod){
mod.fun3 = function () {
//...
};
return mod;
})(module1);
//为module1模块添加了一个新方法fun3(),然后返回新的module1模块。
//引入jquery到项目中;
var Module = (function($){
var _$body = $("body"); // we can use jQuery now!
var foo = function(){
console.log(_$body); // 特权方法
}
// Revelation Pattern
return {
foo: foo
}
})(jQuery)
Module.foo();
概述
特点
基本语法:
exports.xxx = value
// 通过module.exports指定暴露的对象value
module.exports = value
var module = require('模块相对路径')
引入模块发生在什么时候?
exports = {Obj}
,暴露的API须作为此对象的属性。exports本质是引入了module.exports的对象。不能直接将exports变量指向一个值,因为这样等于切断了exports与module.exports的联系。exports=module.exports={Obj}
//结构如下
|-modules
|-module1.js//待引入模块1
|-module2.js//待引入模块2
|-module3.js//待引入模块3
|-app.js//主模块
|-package.json
{
"name": "commonjsnode",
"version": "1.0.0"
}
3.下载第三方模块:举例express
npm i express --save
4.模块化编码
// module1
// 使用module.exports = value向外暴露一个对象
module.exports = {
name: 'this is module1',
foo(){
console.log('module1 foo()');
}
}
// module2
// 使用module.exports = value向外暴露一个函数
module.exports = function () {
console.log('module2()');
}
// module3
// 使用exports.xxx = value向外暴露一个对象
exports.foo = function () {
console.log('module3 foo()');
};
exports.bar = function () {
console.log('module3 bar()');
};
exports.name = 'this is module3'
//app.js文件
var uniq = require('uniq');
//引用模块
let module1 = require('./modules/module1');
let module2 = require('./modules/module2');
let module3 = require('./modules/module3');
//使用模块
module1.foo();
module2();
module3.foo();
module3.bar();
module3.name;
|-js
|-dist //打包生成文件的目录
|-src //源码所在的目录
|-module1.js
|-module2.js
|-module3.js
|-app.js //应用主源文件
|-index.html //浏览器上的页面
|-package.json
{
"name": "browserify-test",
"version": "1.0.0"
}
下载browserify
定义模块代码:index.html文件要运行在浏览器上,需要借助browserify将app.js文件打包编译,如果直接在index.html引入app.js就会报错。
打包处理js:根目录下运行browserify js/src/app.js -o js/dist/bundle.js
页面使用引入:
define([依赖模块名], function(){return 模块对象})
require(['模块1', '模块2', '模块3'], function(m1, m2){//使用模块对象})
define(function (require, exports, module) {
var reqModule = require("./someModule");
requModule.test();
exports.asplode = function () {
//someing
}
});
AMD规范:https://github.com/amdjs/amdjs-api/wiki/AMD
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。
它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:
require([module], callback);
目前,主要有两个Javascript库实现了AMD规范:RequireJS和curl.js。
js/libs/require.js
|-js
|-libs
|-require.js // 引入的require.js
|-modules
|-alerter.js
|-dataService.js
|-main.js
|-index.html
定义require.js的模块代码
define(['myLib'], function(myLib){
function foo(){
myLib.doSomething();
}
// 暴露模块
return {foo : foo};
});
//当require()函数加载上面这个模块的时候,就会先加载myLib.js文件。
- 如果这个模块还依赖其他模块,那么define()函数的第一个参数,必须是一个数组,指明该模块的依赖性;
```
// dataService.js
define(function () {
let msg = 'this is dataService'
function getMsg() {
return msg.toUpperCase()
}
return {getMsg}
})
// alerter.js
define(['dataService', 'jquery'], function (dataService, $) {
let name = 'Tom2'
function showMsg() {
$('body').css('background', 'gray')
alert(dataService.getMsg() + ', ' + name)
}
return {showMsg}
})
```
应用主(入口)js: main.js
(function () {
//配置
require.config({
//基本路径
baseUrl: "js/",
//模块标识名与模块路径映射
paths: {
"alerter": "modules/alerter",//此处不能写成alerter.js,会报错
"dataService": "modules/dataService",
}
})
//引入使用模块
require( ['alerter'], function(alerter) {
alerter.showMsg()
})
})()
页面使用模块:
js/libs/jquery-1.10.1.js
paths: {
'jquery': 'libs/jquery-1.10.1'
}
define(['dataService', 'jquery'], function (dataService, \$) {
var name = 'xfzhang'
function showMsg() {
$('body').css({background : 'red'})
alert(name + ' '+dataService.getMsg())
}
return {showMsg}
})
js/libs/angular.js
// main.js中配置
(function () {
//配置
require.config({
//基本路径
baseUrl: "js/",
//模块标识名与模块路径映射
paths: {
//第三方库作为模块
'jquery' : './libs/jquery-1.10.1',
'angular' : './libs/angular',
//自定义模块
"alerter": "./modules/alerter",
"dataService": "./modules/dataService"
},
/*
配置不兼容AMD的模块
exports : 指定与相对应的模块名对应的模块对象
*/
shim: {
'angular' : {
exports : 'angular'
}
}
})
//引入使用模块
require( ['alerter', 'angular'], function(alerter, angular) {
alerter.showMsg()
console.log(angular);
})
})()
// 没有依赖的模块
define(function(require, module, exports){
let value = 'xxx';
//通过require引入依赖模块
//通过module.exports/exports来暴露模块
exports.xxx = value
module.exports = value
})
// 有依赖的模块
define(function(require, exports, module){
//引入依赖模块(同步)
var module2 = require('./module2')
//引入依赖模块(异步)
require.async('./module3', function (m3) {
......
})
//暴露模块
exports.xxx = value
})
js/libs/sea.js
define()
exports
module.exports
require()
seajs.use()
|-js
|-libs
|-sea.js
|-modules
|-module1.js
|-module2.js
|-module3.js
|-module4.js
|-main.js
|-index.html
定义sea.js的模块代码
define(function (require, exports, module) {
//内部变量数据
var data = 'this is module1'
//内部函数
function show() {
console.log('module1 show() ' + data)
}
//向外暴露
exports.show = show
})
define(function (require, exports, module) {
module.exports = {
msg: 'I Will Back'
}
})
define(function (require, exports, module) {
const API_KEY = 'abc123'
exports.API_KEY = API_KEY
})
define(function (require, exports, module) {
//引入依赖模块(同步)
var module2 = require('./module2');
function show() {
console.log('module4 show() ' + module2.msg)
}
exports.show = show
//引入依赖模块(异步)
require.async('./module3', function (m3) {
console.log('异步引入依赖模块3 ' + m3.API_KEY)
})
})
define(function (require) {
var m1 = require('./module1')
var m4 = require('./module4')
m1.show()
m4.show()
})
index.html:
es6 中新增了两个命令 export 和 import ;
// math.js
export const add = function (a, b) {
return a + b
}
export const subtract = function (a, b) {
return a - b
}
// main.js
import { add, subtract } from './math.js'
add(1, 2)
substract(3, 2)
定义暴露模块 : export
export default 对象
export var xxx = value1
export let yyy = value2
// 暴露一个对象
var xxx = value1
let yyy = value2
export {xxx, yyy}
引入使用模块 : import
import xxx from '模块路径/模块名'
import {xxx, yyy} from '模块路径/模块名'
import * as module1 from '模块路径/模块名'
export不止可以导出函数,还可以导出,对象、类、字符串等等;
暴露多个:
export const obj = {test1: ''}
export const test = ''
export class Test {
constuctor() {
}
}
// 或者,直接在暴露的地方定义导出函数或者变量
export let foo = ()=>{console.log('fnFoo');return "foo"},bar="stringBar"
let a=1
let b=2
let c=3
export { a,b,c }
// test.js
let a = 1
let b = 2
let c = 3
export {
a as test,
b,
c
};
import { test, b, c } from './test.js' // 改变命名后只能写 as 后的命名
// test.js
let a = 1
let b = 2
let c = 3
export {
a as test,
b,
c
};
// lib.js引入test.js的内容
export * from './test.js'
// 引入
import {test,b,c} from './lib.js'
暴露一个对象,默认暴露
// test.js
export default function () {
console.log('hello world')
}
//引入
import say from './test.js' // 这里可以指定任意变量名
say() // hello world
import $ from 'jQuery' // 加载jQuery 库
import _ from 'lodash' // 加载 lodash
import moment from 'moment' // 加载 moment
// main.js
import { add, subtract } from './test'
// 对于export default 导出的
import say from './test'
import {add as sum, subtract} from './test'
sum (1, 2)
// math.js
export const add = function (a, b) {
return a + b
}
export const subtract = function (a, b) {
return a - b
}
//引入
import * as math from './test.js'
math.add(1, 2)
math.subtract(1, 2)
{
"name" : "es6-babel-browserify",
"version" : "1.0.0"
}
npm install babel-cli browserify -g
npm install babel-preset-es2015 --save-dev
{
"presets": ["es2015"]
}
// js/src/module1.js
export function foo() {
console.log('module1 foo()');
};
export let bar = function () {
console.log('module1 bar()');
};
export const DATA_ARR = [1, 3, 5, 1];
// js/src/module2.js
let data = 'module2 data';
function fun1() {
console.log('module2 fun1() ' + data);
};
function fun2() {
console.log('module2 fun2() ' + data);
};
export {fun1, fun2};
// js/src/module3.js
export default {
name: 'Tom',
setName: function (name) {
this.name = name
}
}
// js/src/app.js
import {foo, bar} from './module1'
import {DATA_ARR} from './module1'
import {fun1, fun2} from './module2'
import person from './module3'
import $ from 'jquery'
//引入完毕
$('body').css('background', 'red')
foo()
bar()
console.log(DATA_ARR);
fun1()
fun2()
person.setName('JACK')
console.log(person.name);
引入第三方模块(jQuery)
npm install jquery@1 --save
import $ from 'jquery'
$('body').css('background', 'red')
模块化方案 | 优点 | 缺点 |
---|---|---|
commonJS | 复用性强; 使用简单; 实现简单; |
有不少可以拿来即用的模块,生态不错; 同步加载不适合浏览器,浏览器的请求都是异步加载; 不能并行加载多个模块。 |
AMD | 异步加载适合浏览器 | 可并行加载多个模块; 模块定义方式不优雅,不符合标准模块化 |
ES6 | 可静态分析,提前编译 | 面向未来的标准; 浏览器原生兼容性差,所以一般都编译成ES5; 目前可以拿来即用的模块少,生态差 |
// CMD
define(function(require, exports, module) {
var a = require('./a');
a.doSomething() // 此处略去 100 行
var b = require('./b') // 依赖可以就近书写
b.doSomething() // ... })
// AMD 默认推荐的是
define(['./a', './b'], function(a, b) {
// 依赖必须一开始就写好
a.doSomething() // 此处略去 100 行
b.doSomething()
...})
参考:使用 AMD、CommonJS 及 ES Harmony 编写模块化的 JavaScript