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 的区别

  1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible。
  2. 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(); 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值