ES6 模块的导入导出笔记

ES6 支持 javascript 模块化,模块之间的导入导出有一定的规则,因为总是记不住,做一下学习笔记。

export 导出

export 命令用于规定对外的接口。一个模块就是一个独立的文件,文件内部的变量,外部是无法获取的,如果想读取模块内部的某个变量,必须使用 export 关键字输出该变量。

export 语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。

export 命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错,也就是不能出现在表达式,if 判断等块内。

// export 第一个种写法
export var firstName = "zhangsan";

// 第二种写法,输出一组变量时,一定要有大括号
var secondName = "lisi";
var thirdName = "andy";
export {secondName, thirdName};

// 输出函数
function v1(){}
export {v1}

// 也可以更改输出的名字,对外暴露的就是newFn
export {v1 as newFn}

import 命令

  • 独立加载

不允许修改 import 进来的变量,除非操作的是一个变量中的属性,一般情况下不建议修改变量,仅做只读。

import 命令具有提升效果,会提升到整个模块的头部,首先执行。

由于 import 是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。所谓静态执行,指的是在编译时执行,在程序运行时不执行。

如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次。

// 第一种引入,直接引入输出的,大括号里面的变量名必须与export里面的一一对应
import {firstName,secondName} from './profile.js';

// 第二种写法,改变名称,将lastName 改为 surname
import {lastName as surname} from './profile.js';

// 仅仅执行,不输入。以下仅仅执行lodash模块,但是不输入任何值。
import 'lodash';        
  • 整体加载

整体加载用在不知道导出来的名字,用星号(*)指定一个对象,所有输出值都加载在这个对象上面。

// circle.js
export function area(radius) {
    return Math.PI * radius * radius;
}
  
export function circumference(radius) {
    return 2 * Math.PI * radius;
}

// main.js
// 整体加载
import * as circle from './circle';

console.log('圆面积:' + circle.area(4));
console.log('圆周长:' + circle.circumference(14));

// 下面两行都是不允许的,因为不允许运行时改变
circle.foo = 'hello';
circle.area = function () {};

export default 默认输出

export default 为模块指定默认输出。模块只能有一个 export default,但是可以有多个 export

// export-default.js
export default function () {
    console.log('foo');
}

//   其他函数在加载时,可以以任意名字来加载
// import-default.js
import customName form './export-default';
customName();    // 'foo'   

// 后面不能跟表达式,因为export default 输出的是一个default变量
export default var a = 1;    // 错误

// 当输出 export default 后,可以同时 import 多个
import _, {each, each as forEach} from 'lodash';

// export default 也可以用来输出类。
// MyClass.js
export default class { ... }

// main.js
import MyClass from 'MyClass';
let o = new MyClass();

export 与 import 的复合写法

export 与 import 的复合写法相当于转手导出,当前模块没有引用导出的模块。

export { foo, bar } from 'my_module';
// foo和bar实际上并没有被导入当前模块,只是相当于对外转发了这两个接口,导致当前模块不能直接使用 foo 和 bar。
// 可以简单理解为
import { foo, bar } from 'my_module';
export { foo, bar };


// 接口改名
export { foo as myFoo } from 'my_module';

// 整体输出
export * from 'my_module';

// 具名接口改为默认接口的写法如下。
export { es6 as default } from './someModule';

// 等同于
import { es6 } from './someModule';
export default es6;

// 同样地,默认接口也可以改名为具名接口。
export { default as es6 } from './someModule';

CommonJS 的写法

CommonJS通过 module 对象来把 javascript 代码模块化。引入模块通过 require语法,导出模块通过 module.exports = {} 。范例

// lib.js
var counter = 3;
function incCounter() {
  counter++;
}
module.exports = {
  counter: counter,
  incCounter: incCounter,
};

// 在main.js里面加载这个模块。
// main.js
var mod = require('./lib');

console.log(mod.counter);  // 3
mod.incCounter();
console.log(mod.counter); // 3
// 上面代码说明,lib.js模块加载以后,它的内部变化就影响不到输出的mod.counter了。这是因为mod.counter是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。

读取模块内的数值 需要通过取值器函数。

// lib.js
var counter = 3;
function incCounter() {
  counter++;
}
module.exports = {
  get counter() {
    return counter
  },
  incCounter: incCounter,
};
// 上面代码中,输出的counter属性实际上是一个取值器函数。现在再执行main.js,就可以正确读取内部变量counter的变动了。

$ node main.js
3
4

ES6 模块的引用是复制的引用,一处修改,其他地方都会改。

// lib.js
export let counter = 3;
export function incCounter() {
  counter++;
}

// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4

node 中的 import

目前,Node 的import命令只支持加载本地模块(file:协议),不支持加载远程模块。

如果模块名不含路径,那么import命令会去node_modules目录寻找这个模块。

如果模块名包含路径,那么import命令会按照路径去寻找这个名字的脚本文件。范例

import 'file:///etc/config/app.json';
import './foo';
import './foo?search';
import '../bar';
import '/baz';
/* 如果脚本文件省略了后缀名,比如import './foo',Node 会依次尝试四个后缀名:./foo.mjs、./foo.js、./foo.json、./foo.node。如果这些脚本文件都不存在,Node 就会去加载./foo/package.json的main字段指定的脚本。如果./foo/package.json不存在或者没有main字段,那么就会依次加载./foo/index.mjs、./foo/index.js、./foo/index.json、./foo/index.node。如果以上四个文件还是都不存在,就会抛出错误。

最后,Node 的import命令是异步加载,这一点与浏览器的处理方法相同 。

参考链接:http://es6.ruanyifeng.com/#docs/module

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

推荐阅读更多精彩内容