JavaScript模块化教程
js是一种脚本语言,与php类似。但是如今php不再仅仅构建一个简单的web,它也在向java看齐,也能够支撑起一个庞大的web系统。国外非常有名的脸书网就是一个典型的例子。一门语言,要构建出庞大复杂的系统的基础之一就是语言文件的相互引用。毕竟一个单文件直接实现一个庞大复杂的系统是十分吃力的。
后端模块化
commonjs
在互联网早期,javascript 一直在前端发光发热,但在后端基本上没有什么建树。并且 javascript 官方的一些规范也仅仅只是对于前端做了很多要求,没有考虑到后端,这样导致 javascript 一直寄生于中。但是 javascript 社区不满足仅仅让 javascript 这门语言只存在于浏览器里,他们希望能够在任何地方都能运行 javascript。于是,commonjs 应运而生,它是社区制定的一份 javascript 规范。
commonjs 涵盖的内容
模块 二进制 buffer 字符集编码 i/o流 进程环境 文件系统 套接字 单元测试 web服务器网关接口 包管理 …
commonjs 的模块规范
commonjs 的模块规范很简单,主要包含三部分,模块定义,模块标识以及模块引用。
模块引用
示例如下:
var math = require('math');
主要使用了require()方法,他接受一个参数,模块标识。
模块定义
示例如下:
exports.add = function (a, b) { return a + b; };
主要使用了exports对象,只要将方法挂载在exports对象上作为属性即可定义导出的方式。
下面给出一个模块引入及使用的例子:
var math = require('math'); exports.getall = function (x, y) { return math.add(x, y); };
模块标识
模块标识就是传递给require()方法的参数,他要求是符合小驼峰命名的字符串,或者以.,..开头的相对路径,或者绝对路径。他可以没有文件后缀名js。
commonjs 与 node.js
commonjs 只是定义了一份模块的规范,而 node.js 根据这份规范实现了模块机制。这好比接口和实现类,一个给出了接口,另一个真正实现了接口,但是实现可能有很多种不同的方式。
前端模块化
说完后端模块化,我们再来聊一聊前端模块化。
如何去实现前端的模块化呢?
有人可能会说,这还不简单,既然后端模块化已经可以良好的工作了,那我们直接照搬到前端不就可以了嘛!
理论上是的,但是现实中却遇到了一个大问题。我们要知道在后端,文件的 i/o 很快,因为我们直接在服务器的硬盘上读写文件即可。但是在前端可不是这个样子,所有文件的 i/o 都是要经过 http 请求去完成的,网络延时是个大问题。
如果一个页面空白3秒钟以上,那么用户肯定会不爽,一般他们会刷新,如果刷新页面几次都不能看到页面,那可能会直接关掉页面,甚至以后都不会再次访问你的站点。
所以,在前端我们实现模块化不能仿照后端那样,进行同步加载,最好的方式就是异步加载。而在前端比较火的两个异步加载规范就是 amd 和 cmd。
amd
全称:asynchronous module definition,异步模块定义 amd 是 requirejs 在过程中对模块定义的规范化产出在 amd 规范中,一个模块就是一个文件。该规范的核心就是define()函数,define() 是一个全局函数,用来定义模块。
define(id, dependencies, factory);
下面给出一个示例:
define("types/manager", ["types/employee"], function (employee) { function manager () { this.reports = []; } //开始执行 manager.prototype = new employee(); //返回经理构造函数可以由其他模块的应用。 return manager; } );
cmd
全称:common module definition,公共模块加载 cmd 是 seajs 在推广过程中对模块定义的规范化产出
在 cmd 规范中,一个模块就是一个文件。该规范的核心就是define()函数,define() 是一个全局函数,用来定义模块。
define(function(require, exports, module) { // 模块代码 });
下面给出一个示例:
define(function(require, exports, module) { // 通过 require 引入依赖 注意 .js 可以省略 var $ = require('jquery'); // 你也可以引入自己的函数依赖 var spinning = require('./yourfunction'); var util = {}; util.sayhello = function(){ return 'seajs向你问好'; } // 通过 exports 对外提供接口 module.exports = util; });
amd 和 cmd 的区别
对于依赖的模块,amd 是提前执行,cmd 是延迟执行。不过 requirejs 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。cmd 推崇 as lazy as possible。 cmd 推崇依赖就近,amd 推崇依赖前置。// 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() ... })
es6
es6 这个词的原意,就是指 javascript 语言的下一个版本,他由国际标准化组织ecma提出。es6 模块是编译时加载,而commonjs 模块是运行时加载。
es6 模块功能主要由两个命令构成:export和import。
export命令用于规定模块的对外接口 import命令用于输入其他模块提供的功能
export命令
输出变量
export var firstname = 'michael';
输出函数
export function multiply(x, y) { return x * y; };
使用大括号输出的一组变量
var firstname = 'michael'; var lastname = 'jackson'; var year = 1958; function f() {} export {firstname, lastname, year, f};使用as关键字重命名
function v1() { ... } function v2() { ... } export { v1 as streamv1, v2 as streamv2, v2 as streamlatestversion };
import 命令
import命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。
引入变量
import {firstname, lastname, year} from './profile'; function setname(element) { element.textcontent = firstname + ' ' + lastname; }
使用as关键字重命名
import { lastname as surname } from './profile';
执行加载模块
import 'lodash';
整体加载
import * as circle from './circle'; console.log('圆面积:' + circle.area(4)); console.log('圆周长:' + circle.circumference(14));
export default 命令
export default function () { console.log('foo'); }
其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。
import customname from './export-default'; customname();
上一篇: 微信小程序框架wepy之动态控制类名
下一篇: 详解vue 数组和对象渲染问题