JS-使用ES6模块化的注意点

一直以来javascript的模块化要么使用commonJS,要么使用AMD,在ES6中开始支持模块化了,关键字主要有import(导入)和export(导出)。最近一段时间一直在思考ES6中的模块化与我们正常使用的AMD(如requireJS),以及commomJS(如nodeJS)有何不同。在搜索了相关的资料后,发现ES6模块化中有些地方很值得注意。

ES6模块是静态加载

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

import 和 export 命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错。这是因为处于条件代码块之中,就没法做静态优化了,违背了ES6模块的设计初衷。以下的写法会报错

// 报错
if (x === 1) {
    import { foo } from 'module1';
} else {
    import { foo } from 'module2';
}

// 报错
function foo() {
    export default 'bar' // SyntaxError
}
foo()

import

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

// 报错
import { 'f' + 'oo' } from 'my_module';

// 报错
let module = 'my_module';
import { foo } from module;

// 报错
if (x === 1) {
  import { foo } from 'module1';
} else {
  import { foo } from 'module2';
}

上面三种写法都会报错,因为它们用到了表达式、变量和if结构。在静态分析阶段,这些语法都是没法得到值的。

2.import语句会执行所加载的模块.如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次。

3.模块的整体加载

// 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),应该是可以静态分析的,所以不允许运行时改变。下面的写法都是不允许的。

//main.js
import * as circle from './circle';
// 下面两行都是不允许的
circle.foo = 'hello';
circle.area = function () {};

export

1.export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。

// 报错
export 1;

// 报错
var m = 1;
export m;

上面两种写法都会报错,因为没有提供对外的接口。第一种写法直接输出1,第二种写法通过变量m,还是直接输出1。1只是一个值,不是接口。正确的写法是下面这样。

// 写法一
export var m = 1;

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

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

上面三种写法都是正确的,规定了对外的接口m。其他脚本可以通过这个接口,取到值1。它们的实质是,在接口名与模块内部变量之间,建立了一一对应的关系。

2.export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。这一点与 CommonJS 规范完全不同。CommonJS 模块输出的是值的缓存,不存在动态更新。

export 和 import 使用的例子

1.export {} + import {}

// jq.js
function myfun () {
    console.log('excuted');
}
export {
    myfun
}

引入方式:

import {myfun} from 'js/jq';
//执行
myfun();

2.export {} + import * as xxx

// jq.js
function myfun () {
    console.log('excuted');
}
export {
    myfun
}

引入方式:

import * as fn from 'js/jq';
//执行
fn.myfun();

3.import default + export xxx

// jq.js
function myfun () {
    console.log('excuted');
}
export default {
    myfun
}

引入方式:

import fn from 'js/jq';
//执行
fn.myfun();

参考资料
ECMAScript 6 入门-Module 的语法

猜你喜欢

转载自blog.csdn.net/zhq2005095/article/details/72962999