ES6 学习笔记(17) Module 的语法

1. 概述


由于 ES6 模块是编译时加载,使得静态分析成为可能。有了它,就能进一步拓宽 JavaScript 的语法,比如引入宏(macro)和类型检验(type system)这些只能靠静态分析实现的功能。

除了静态加载带来的各种好处,ES6 模块还有以下好处。

不再需要UMD模块格式了,将来服务器和浏览器都会支持 ES6 模块格式。目前,通过各种工具库,其实已经做到了这一点。
将来浏览器的新 API 就能用模块格式提供,不再必须做成全局变量或者navigator对象的属性。
不再需要对象作为命名空间(比如Math对象),未来这些功能可以通过模块提供。

2. 严格模式


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

变量必须声明后再使用
函数的参数不能有同名属性,否则报错
不能使用with语句
不能对只读属性赋值,否则报错
不能使用前缀0表示八进制数,否则报错
不能删除不可删除的属性,否则报错
不能删除变量delete prop,会报错,只能删除属性delete global[prop]
eval不会在它的外层作用域引入变量
evalarguments不能被重新赋值
arguments不会自动反映函数参数的变化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局对象
不能使用fn.callerfn.arguments获取函数调用的堆栈
增加了保留字(比如protectedstaticinterface

3. export 命令


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

  // 写法一
  export var m = 1;

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

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

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

4. import 命令


使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。
最后,import语句会执行所加载的模块,因此可以有下面的写法。

  import { foo } from 'my_module';
  import { bar } from 'my_module';
  // 等同于
  import { foo, bar } from 'my_module';

5. 模块的整体加载


除了指定加载某个输出值,还可以使用整体加载,即用星号(*)指定一个对象,所有输出值都加载在这个对象上面。

  // circle.js  导出模块

  export function area(radius) {
    return Math.PI * radius * radius;
  }

  export function circumference(radius) {
    return 2 * Math.PI * radius;
  }
  // 整体引入
  import * as circle from './circle';
  console.log('圆面积:' + circle.area(4));
  console.log('圆周长:' + circle.circumference(14));

6. export default 命令


为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。

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

  // 或者写成

  function foo() {
    console.log('foo');
  }

  export default foo;

如果想在一条import语句中,同时输入默认方法和其他接口,可以写成下面这样。

  import _, { each, each as forEach } from 'lodash';

7. export 与 import 的复合写法


如果在一个模块之中,先输入后输出同一个模块,import语句可以与export语句写在一起。

  export { foo, bar } from 'my_module';

  // 可以简单理解为
  import { foo, bar } from 'my_module';
  export { foo, bar };

模块的接口改名和整体输出,也可以采用这种写法。

  export { es6 as default } from './someModule';

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

8. 模块的继承


假设有一个circleplus模块,继承了circle模块。

  // circleplus.js

  export * from 'circle';
  export var e = 2.71828182846;
  export default function(x) {
    return Math.exp(x);
  }

9. 跨模块常量


本书介绍 const 命令的时候说过, const 声明的常量只在当前代码块有效。如果想设置跨模块的常量(即跨多个文件),或者说一个值要被多个模块共享,可以采用下面的写法。

  // constants.js 模块
  export const A = 1;
  export const B = 3;
  export const C = 4;

  // test1.js 模块
  import * as constants from './constants';
  console.log(constants.A); // 1
  console.log(constants.B); // 3

  // test2.js 模块
  import {A, B} from './constants';
  console.log(A); // 1
  console.log(B); // 3

10. import()


因此,有一个提案,建议引入import()函数,完成动态加载。
import()返回一个 Promise 对象。下面是一个例子。

你可能感兴趣的:(ES6 学习笔记(17) Module 的语法)