JS模块化

1 模块化

1.1 模块化的含义

模块化是指将一个复杂的程序依据一定的规则(规范)封装成几个块(文件),并进行组合在一起。
最早我们开发将所有的代码写在一个js文件中,随着需求越来越复杂,代码量越来越大,如果仍然把所有代码写在一个js文件中,那么代码耦合度过高不方便后期维护,也不方便程序员找到某一个功能点的代码,所有东西写在一个文件也容易污染全局环境。模块化将一个复杂的js文件按共同或类似的逻辑拆分成多个js文件,拆封的文件内部数据是私有的,只是向外部暴露一些接口(方法)与其他模块通信,不仅方便找到某一块功能点的代码,也可以达到复用的效果。

1.2 模块化的发展历史

  • 最早直接在一个js文件中定义,全局环境污染,很容易命名冲突。
function foo() {
  //...
}
function fun() {
  //...
}
  • Namespace模式,把数据放到对象里面简单封装,减少全局的变量数目,但本质上是对象,可以通过对象.属性修改数据,一点都不安全。
var obj = {
  foo: function() {},
  fun: function() {}
}
obj.foo();
  • IIFE(立即执行函数)模式,在全局看不到函数内部数据,相对来说安全。
var Module = (function() {
  var _private = "hello";
  var foo = function() {
    //...
  }
  return {
    foo: foo
  }
})()
Module.foo();
console.log(Module._private); // undefined 全局下获取不到函数内部数据_private
  • 引入依赖,通常依赖以实参的形式注入。
var Module = (function($) {
  var _$body = $("body"); // 使用依赖
  var foo = function() {
    //...
    console.log(_$body);
  }
  return {
    foo: foo
  }
})(jQuery)
Module.foo();

2 模块化规范

在模块化之前原本只有一个js文件,只需要用一个script标签,发送一次http请求,现在将一个js文件拆分成多个,意味着需要使用多个script标签,发送多次请求。并且如果模块之间有依赖,引入加载script标签的顺序不能换。
模块化规范就是为解决这些问题,常用的模块化规范有:

  • CommonJS
  • AMD
  • CMD
  • ES6

2.1 CommonJS

Node.js的实现让js也可以成为后端开发语言,但在早先Node.js开发过程中并没有像其他后端语言一样有包引入和模块系统的机制,于是CommonJS创造了一套js模块系统的规范。

CommonJS在服务器端渲染时,模块的加载运行是同步的。如果浏览器端向服务器端发请求要一个模块,而服务器端前面还需要加载好几个模块,那么意味着浏览器端发送了请求但需要排队等待,用户体验差。还有浏览器端不认识CommonJS的require语法,所以在浏览器端使用CommonJS,模块需要提前编译打包处理。
基本语法:

  • 暴露模块module.exports = valueexports.xxx = value,暴露的模块是一个对象
  • 引入模块require(xxx),引入第三方模块xxx为模块名,引入自定义模块xxx为模块文件路径

2.1.1 基于服务器端Node.js应用

// 使用 module.exports = value 暴露一个对象
module.exports = {
  msg: 'module1',
  foo() {
    console.log(this.msg);
  }
}
// 使用 module.exports = value 暴露一个函数
module.exports = function() {
  console.log('module2');
}
// 使用 exports.xxx = value 暴露
exports.foo = function() {
  console.log('foo() module3');
};
exports.fun = function() {
  console.log('fun() module3');
};
exports.arr = [1, 2, 1];
// 将其他模块汇集到主模块
// 引入下载的第三方模块(npm install uniq)
let uniq = require('uniq');
// 引入自定义模块
let module1 = require('./xxx/module1');
let module2 = require('./xxx/module2');
let module3 = require('./xxx/module3');

// 使用这些模块
module1.foo();
module2();
module3.foo();
module3.fun();
let result = uniq(module3.arr);

通过node命令运行app.jsnode app.js

2.1.2 基于浏览器端Browserify应用

  1. 下载Browserify
    全局安装:npm install browserify -g
    局部安装:npm install browserify --save-dev
  2. 打包处理app.js
    browserify xxx/src/app.js -o xxx/dist/bundle.js
  3. index.html页面使用引入
    <script type="text/javascript" src="xxx/dist/bundle.js"></script>

2.2 AMD

AMD模块化规范专门用于浏览器端,在浏览器端模块的加载是异步的,依赖库require.js(RequireJS官网下载地址)。
基本语法:

  • 定义暴露模块
    定义没有依赖的模块define(function() { return 模块 })
    定义有依赖的模块define(['module1', 'module2'], function(m1, m2) { return 模块 })
  • 引入使用模块require(['module1', 'module2'], function(m1, m2) { 使用m1 m2 })

2.2.1 require.js应用

// 定义没有依赖的模块
define(function() {
  let name = 'dataService.js';
  function getName() {
    return name;
  }
  // 暴露模块
  return { getName };
});
// 定义有依赖的模块
define(['dataService'], function(dataService) {
  let msg = 'alerter.js';
  function showMsg() {
    console.log(msg, dataService.getName());
  }
  // 暴露模块
  return { showMsg };
});
// 将其他模块汇集到主模块
(function() {
  // 配置路径
  requirejs.config({
    baseUrl: 'xxx/xxx',
    paths: {
      dataService: './xxx/dataService',
      alerter: './xxx/alerter',
    }
  });
  // 引入使用模块
  requirejs(['alerter'], function(alerter) {
    alerter.showMsg();
  })
})()

index.html页面使用引入<script data-main="xxx/main.js" src="xxx/require.js"></script>

2.3 CMD

2.4 ES6

ES6语法目前还有浏览器不支持,开发结束还需要使用Babel将ES6编译为ES5代码,在转化过程中使用的require语法浏览器引擎不认识,依赖模块需要编译打包处理。
基本语法:

  • 暴露模块export
  • 引入模块import

2.4.1 应用

// 分别暴露
export function foo() {
	console.log('foo() module1');
}
export function fun() {
	console.log('fun() module1');
}
export let arr = [1, 2, 3]
// 统一暴露
function fn() {
  console.log('fn() module2');
}
function fn2() {
  console.log('fn2() module2');
}
export { fn, fn2 };
// 默认暴露
export default () => {}
export default {
  msg: 'hello',
  foo(){
    console.log(this.msg);
  }
}
// 引入其他模块
import $ from 'jquery'; // 引入第三方模块
import {foo, fun, arr} from './xxx/module1';
import {fn, fn2} from './xxx/module2';
import module3 from './xxx/module3';
  1. 安装babel-cli,babel-preset-es2015和browserify
    npm install babel-cli browserify -g
    npm install babel-preset-es2015 --save-dev
  2. 在根目录下配置.babelrc文件
{
  "presets": ["es2015"]
}
  1. 编译
    使用Babel将ES6编译为ES5代码babel js/src -d js/lib
    使用Browserify编译jsbrowserify js/lib/main.js -o js/lib/bundle.js
  2. index.html页面使用引入
    <script type="text/javascript" src="js/lib/bundle.js"></script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值