前端模块化范例笔记

现在通行的Javascript的模板范例共有两种:CommonJSAMD

commonjs

nodejs的模块体系,是参照commonjs范例完成的

commonjs即为服务器端模块的范例。 commonjs的范例: 依据commonjs范例,一个零丁的文件就是一个模块。加载模块运用require要领,该要领读取一个文件并实行,末了返回文件内部的exports对象

commonjs模块的加载道理

commonjs模块不管加载多少次,都只会在第一次加载时运转一次,今后再加载,就返回第一次运转的结果,除非手动消灭体系缓存。

AMD

commonjs范例加载模块是同步的,也就是说,只需加载完成,才实行背面的操纵。AMD范例则是非同步加载模块,许可指定回调函数。由于Node.js重要用于服务器编程,模块文件平常都已存在于当地硬盘,所以加载起来比较快,不必斟酌非同步加载的体式格局,所以commonjs范例比较实用。然则,假如是浏览器环境,要从服务器端加载模块,这时候就必需采纳非同步情势,因而浏览器端平常采纳AMD范例。

能够理解为AMD即为能在客户端环境,而且能兼容服务器端模块的一种模块范例

  • AMD的模块定义:
    AMD范例运用define要领定义模块

    Define第一个参数表达依靠的模块数组,第二个为加载完依靠的模块数组后,模块实行的函数
    
  • AMD的模块加载定义:跟commonjs一样,AMD也采纳require()语句来加载模块,然则与commonjs差别的是,它请求有两个参数:
    第一个参数[module],是一个数组,内里的成员就是要加载的模块;第二个参数callback,则是加载胜利以后的回调函数

AMDCMD对照

  1. 关于依靠的模块,AMD是提早实行,CMD是耽误实行。不过 RequireJS 从 2.0 最先,也改成能够耽误实行(依据写法差别,处理体式格局差别)。CMD推重 as lazy as possible.

  2. CMD推重依靠就近,AMD推重依靠前置

  3. AMDAPI默许是一个当多个用,CMD的API 严厉辨别,推重职责单一。比方AMD里,require分全局require和部分require,都叫requireCMD里,没有全局 require,而是依据模块体系的完整性,供应seajs.use来完成模块体系的加载启动。CMD里,每一个API都简朴地道。

ES6 Modules

ES6模块的设想头脑,是只管的静态化,使得编译时就可以肯定模块的依靠关联,以及输入和输出的变量。commonjsAMD模块,都只能在运转时肯定这些东西。比方,commonjs模块就是对象,输入时必需查找对象属性。

// CommonJS模块
let { stat, exists, readFile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat, exists = _fs.exists, readfile = _fs.readfile;

上面代码的本质是团体加载fs模块(即加载fs的一切要领),天生一个对象(_fs),然后再从这个对象上面读取3个要领。这类加载称为“运转时加载”,由于只需运转时才获得这个对象,致使完整没办法在编译时做“静态优化”。

ES6模块不是对象,而是经由过程export敕令显式指定输出的代码,输入时也采纳静态敕令的情势。

// ES6模块
import { stat, exists, readFile } from 'fs';

上面代码的本质是从fs模块加载3个要领,其他要领不加载。这类加载称为“编译时加载”,即ES6能够在编译时就完成模块加载,效力要比CommonJS模块的加载体式格局高。固然,这也致使了没法援用ES6模块自身,由于它不是对象。

由于ES6模块是编译时加载,使得静态剖析成为可能。有了它,就可以进一步拓宽JavaScript的语法,比方引入宏(macro)和范例磨练(type system)这些只能靠静态剖析完成的功用。

除了静态加载带来的种种优点,ES6模块另有以下优点。

不再须要UMD模块花样了,将来服务器和浏览器都邑支撑ES6模块花样。现在,经由过程种种东西库,实在已做到了这一点。
将来浏览器的新API就可以用模块花样供应,不再必要做成全局变量或许navigator对象的属性。
不再须要对象作为定名空间(比方Math对象),将来这些功用能够经由过程模块供应。
浏览器运用ES6模块的语法以下。

<script type=”module” src=”foo.js”></script>
上面代码在网页中插进去一个模块foo.js,由于type属性设为module,所以浏览器晓得这是一个ES6模块。

Node的默许模块花样是CommonJS,现在还没决议怎样支撑ES6模块。所以,只能经由过程Babel如许的转码器,在Node内里运用ES6模块。

用法

export
优先斟酌这类写法而不是一个一个的export

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};

供应对外接口必需在接口名与模块内部变量之间坚持一一对应关联

// 报错
function f() {}
export f;

// 准确
export function f() {};

// 准确
function f() {}
export {f};

末了,export敕令能够出现在模块的任何位置,只需处于模块顶层就可以够。假如处于块级作用域内,就会报错,下一节的import敕令也是云云。这是由于处于前提代码块当中,就没法做静态优化了,违犯了ES6模块的设想初志。

import
运用export敕令定义了模块的对外接口今后,其他JS文件就可以够经由过程import敕令加载这个模块(文件)。

// main.js

import {firstName, lastName, year} from './profile';

function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}

上面代码的import敕令,就用于加载profile.js文件,并从中输入变量。import敕令接收一个对象(用大括号示意),内里指定要从其他模块导入的变量名。大括号内里的变量名,必需与被导入模块(profile.js)对外接口的称号雷同。

假如想为输入的变量从新取一个名字,import敕令要运用as关键字,将输入的变量重定名。

import { lastName as surname } from './profile';

注重,import敕令具有提拔结果,会提拔到全部模块的头部,起首实行。

ES6模块加载的本质

ES6模块加载的机制,与CommonJS模块完整差别。CommonJS模块输出的是一个值的拷贝,而ES6模块输出的是值的援用。
ES6的输入有点像Unix体系的“标记衔接”,原始值变了,import输入的值也会随着变。因而,ES6模块是动态援用,而且不会缓存值,模块内里的变量绑定其地点的模块。

参考资料

IMWEB团队博客
知乎问答
阮一峰先生的ES6教程

    原文作者:jasminecjc
    原文地址: https://segmentfault.com/a/1190000006058521
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞