您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

ES6+ 模块化(二)

要深入前端学习时绕不开的是 Node 的学习,而 Node 中了模块化系统,Node 中的模块化是基于 CommonJS 规范实现的。而 ES6 中的模块化与之还有很多的不同的地方。现阶段 Node 还依然使用的是 CommonJS 规范,而前端正在逐渐使用 ES6 module 规范。两个规定统一是漫长的过程,两者都存在历史遗留问题和兼容问题需要浏览器和 Node 核心的。有必要搞清楚两个规范的区别和注意事项,有助于我们深入地学习前端。

上一节我们学习 ES6 Module 的环境搭建和基本,本节将继续学习模块化的相关知识,本节主要是学习 CommonJS 规范,还有对比 ES6 module 规范的一些区别和注意事项。

在维基百科中是这样定义 CommonJS 的:

CommonJS 是项目,其目标是为 JavaScript 在网页浏览器之外创建模块约定。创建这个项目的主要原因是当时缺乏普遍可接受形式的 JavaScript 脚本模块单元,模块在与运行 JavaScript 脚本的常规网页浏览器所提供的不同的环境下可以重复使用

JavaScript 语言在很长一段时间是没有模块化的概念的,直到 Node.js 的诞生后,让 JavaScript 有能力编写服务端语言,对操作系统、网络、系统等等的复杂业务场景,使用模块化就是不可或缺。这样也把模块化的概念带到了前端,而这时的客户端的也很复杂,急需一种可以拆分模块方便管理的一种模式。最终在社区的推动下 ES6 给出了 JavaScript 模块化的规范。

在 Node 模块中,CommonJS 规定每个就是模块,有它自己的作用域。在里面定义的变量、、类,都是私有的,对其他不可见。

CommonJS 规定每个模块内部,module 变量代表当前模块。这个变量是对象,它的 exports (即 module.exports)是对外的接口。加载某个模块,其实是加载该模块的 module.exports

使用 module.exports 把需要暴露的导出,没有导出的在外面是访问不了的。

// a.js
module.exports.name = 'imooc';
module.exports.fn = function(){}
const age = ;

上面的中在 a.js 中相当于私有的作用域, module.exports 把 name 和 fn 两个变量导出,但是 age 没有导出,所以在外部是访问不了的。

为了方便 module.exports 也可以省略 module 直接使用 exports 进行导出操作:

exports.a = 'hello'

使用 module.exports 时还可以整体导出,整体导出时不能简写 exports

module.exports = { name: 'imooc', fn:function(){} }

使用 require 用于导入其他模块暴露出来的。导出的是对象。

const a = require('./a');
console.log(a);	// { name: 'imooc', fn: [Function (anonymous)] }

使用 import 命令加载 CommonJS 模块,Node 会将 module.exports 当作模块的认,即等同于 export default

// a.js
module.exports = {
  foo: 'hello',
  bar: 'world'
}

// 在import引入时等同于
export default {
  foo: 'hello',
  bar: 'world'
}

CommonJs 模块是运行时确定接口,所以采用 import 命令加载 CommonJS 模块时,只能使用整体输入(*)。

import {readfile} from 'fs' //当'fs'为CommonJS模块时
// 整体输入
import * as express from 'express'
const app = express.default();

require 命令加载 ES6 模块时,所有的接口都会成为输入对象的。

// es.js
let foo = {bar : 'my-default'};
exxport default foo;
foo = null;

// cjs.js
const es_namespace = require('./es')
console.log(es_namespace.default);// {bar:'my-default'}

模块化在面试中经常会被问到,掌握其深层原理是回答这类问题的关键。下面是面试中参考的两道题,这里和大家一下,提供的答案仅供参考。

两个规范的区别可以从以下几个方面来回答:

JS 在加载时分为两个阶段:编译和执行,而 ES6 模块是在 编译时进行加载(也可以叫:静态加载),这使得静态分析成为可能。es module 采用严格模式,不管你有没有在模块头部 "use strict";

这是一道经典的 commonjs 的面试题,分析下列这段,并解释原理。

//main.js
var a = require('./a')
console.log(a)

// a.js
module.exports.a = 
var b = require('./b')
console.log(b)
module.exports.a = 

// b.js
module.exports.b = 
var a = require('./a')
console.log(a)
module.exports.b = 

回答本题的核心就是要知道 require 后的模块是会被缓存的,还需要注意的是先加入缓存,然后再执行。这样在按照同步的执行顺序去分析就会很清晰。具体分析如下:

本节主要学习了 CommonJS 的使用、在 CommonJS 和 ES Module 混用的一些问题,最后通过两道面试题学习了两个规范的区别和 CommonJS 在使用时会存在循环引用的问题,并分析了其执行的顺序和缓存的特点。


联系我
置顶