Module 模块加载

ES6 模块规范

ES6 的模块功能主要由两个命令构成: exportimport
export 命令用于规定模块的对外接口。
import 命令用于输入其他模块提供的功能。

ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";。


export 命令

export 的写法如下:

// 写法一
export var foo = 1;

// 写法二
var foo = 1;
export {foo };

// 写法三
var foo = 1;
export {n as foo };

foo 可以是变量,常量,函数function 或 类class



import 命令

// 写法一
import { foo } from 'util'
import { bar} from 'util'


// 写法二
import { foo, bar } from 'util'


// 写法三
import { foo as surname } from 'util';

// 写法四
import * as u from 'util';
console.log(u.foo, u.bar)

01
import 后面的 from 指定模块文件的位置,可以是相对或绝对路径,.js 后缀可以省略。
如果只是模块名,不带路径,那么必须有配置文件来告诉JavaScript引擎该模块的位置。
例如上面的 util 是模块文件名,由于不带有路径,必须是配置过的,告诉引擎怎么获取这个模块。

02
import命令输入的变量都是只读的,不允许在加载模块的脚本里面改写接口。

import {a} from './xxx.js'

a = {}; // Syntax Error : 'a' is read-only;
a.foo = 'hello'; // 合法操作

上面代码中,脚本加载了变量a,对其重新赋值就会报错,因为a是一个只读的接口。但是,如果a是一个对象,改写a的属性是允许的。
第三行中a的属性被成功改写,并且其他模块也可以读到改写后的值。不过,这种写法很难查错,不建议这么做

03
import 语句是 Singleton 模式的。既同一个模块实例被 import 两次时,只会执行一次。

04
目前阶段,通过 Babel 转码,CommonJS 模块的require命令和 ES6 模块的import命令,可以写在同一个模块里面,但不建议这样做



export default 命令

export default 的写法如下:

// 写法一
export default function () { console.log('foo') }

// 写法二
export default function foo() { console.log('foo') }

// 写法三
function foo() { console.log('foo') }
export default foo

export default 命令可以使用匿名函数或非匿名函数。
但是非匿名函数的的函数名在模块外是无效的。在模块外加载时视同非匿名函数来加载。

01 export 和 export default 在输入上的不同

// 第一组
export function crc32() { // 输出
  // ...
};
import { crc32 } from 'crc32'; // 输入 当不用 as 时import 必须与 export 的名字相同


// 第二组
export default function crc32() { // 输出
  // ...
}
import c from 'crc32'; // 输入  可为该匿名函数指定任意名字

对比上面两种写法可知,使用 export default 时, 对应的 import 语句不需使用大括号。
这样的好处是当开发一些第三库时,用户未必愿意去了解模块有哪些属性和方法,这时为了用户方便,就可以用 export default 命令,为模块指定默认输出啦。

02 export 和 export default在定义时的不同export default就是输出一个叫做default`的变量或方法

// 正确
export var a = 1;

// 正确
var a = 1;
export default a;

// 错误
export default var a = 1;

上面代码中,export default a的含义是将变量a的值赋给变量default。所以,最后一种写法会报错。

同样地,因为export default命令的本质是将后面的值,赋给default变量,所以可以直接将一个值写在export default之后。

// 正确
export default 42;

// 报错
export 42;







CommonJS 模块规范

在 ES6 之前,社区指定了一些模块加载方案,主要的有 CommonJS 和 AMD 两种,前者用户服务器,后者用于浏览器。比如 CommonJS 模块是对象输出,输入时不需查找对象属性。

ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。


module.exports 与 require

我们所熟悉的 NodeJS 由模块组成,采用的就是CommonJS 模块规范。

CommonJS定义的模块分为: 模块标识(module)、模块定义(exports) 、模块引用(require)

CommonsJS 规范规定,每个模块内部, module 变量代表当前模块。这个模块是一个对象,她的 exports 属性,来表示对外的接口(既 module.exports 是对外的接口)。
例如

var num = 5;
var add = function (value) {
  return value + x;
};
module.exports.num  = num;
module.exports.add = add;

上面代码的输入格式如下:

let { num, add } = require('util');

// 或者
let _util = require('util');
console.log( _util.num ) //5
console.log( _util.add(1) ) //6


module.exports 与 exports

为了方便,Node 为每一个模块提供一个 exports 变量,指向 module.exports。
他们的关系是:
exports = module.exports = {};

  • exports 是 module.exports 的一个引用,指向同一个内存地址;
  • module.exports 初始值为一个空对象{}, 所以 exports 初始值也是 {};
  • exports.xxx = 相当于在导出对象上挂属性,该属性对调用模块直接可见;
  • exports = 相当于给 exports 对象重新赋值,会切断了 exports 与 module.exports 的联系,所以建议使用 module.exports

如果对上面说的一堆不理解,来看下面的例子:

// requireMe.js
// exports = function(){} // 错误写法 ,这样相当于直接给 exports 赋值
exports.something = function(){  console.log('hello world') }
// index.js
var something = require('./requireMe');
something();
// 报错,因为 require 出来的 module.exports 是一个 object,不能直接执行


//修改方式一
// requireMe.js
module.exports = function(){  console.log('hello world') }
// 不报错,因为此时的 module.exports 是一个 function, 可以直接执行。


// 修改方式二
// index.js
var something = require('./requireMe');
something.something();
// 因为这时候 require 出来的是一个 object,有一个 something 的属性,所以可以这样调用执行。





参考文章:
阮一峰:Module 语法
liaofy:module.exports与exports,export与export default之间的关系和区别




希望这篇文章能帮助到你
END

\color{#ccc}{liwuwuzhi}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容