ESM

ES Module 是官方的模块化规范,一个文件就是一个模块,该文件内的所有变量外部无法获取,如果希望外部能够读取模块内部的某个变量,就必须使用export关键字导出,一个模块如果需要使用其它模块的变量,就需要使用import导入被引用模块export的变量;

命名导出

// profile.js,输出三个变量
export const firstName = "Michael";
export const lastName = "Jordan";
export const year = 1958;

// 也可以写成以下形式
const firstName = "Michael";
const lastName = "Jordan";
const year = 1958;
export {firstName, lastName, year};

// 也支持输出函数或者类
export function say(){
  return "Hello";
}

// 可以使用关键字as重命名输出变量
export {
  firstName,
  familyName as lastName,
  year
};

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

// 报错
export 1;

// 报错,通过变量还是直接输出1,不是接口
const m = 1;
export m;

// 写法一
export const m = 1;

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

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

导入 import

使用import命令可以加载模块,并接受模块中通过export导出的内容;

import { firstName, lastName, year } from './profile';

function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}

// 同样也可以使用as设置引用变量别名
import { lastName as familyName } from './profile';


// 命名空间引入:使用`*`导入整个模块到一个对象,通过这个对象引用模块`export`的全部接口
import * as jordan from './profile';
console.log(jordan.firstName);// Michael

注意import具有提升效果,会提升到整个模块的顶部,首先执行;

foo();// 可以正确执行,不会报错;
import { foo } from 'my_module';

仅运行:某些情况我们需要运行其它模块的代码,但是并不需要引入其导出的的变量,我们可以使用写法import 'lodash';,被导入模块的全局代码会被运行,如果多次加载只会执行一次。

默认导出

以上的例子中使用import命令时用户需要知道加载的变量名或函数名,这个体验很不好,通过export default命令可以指定模块的默认输出

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

// import-default.js
import customName from './export-default';
customName(); // 'foo'

使用import命令加载 default 输出是不需要使用大括号的; export default命令用于指定模块的默认输出。一个模块只能有一个默认输出,因此export default命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能对应一个方法。

本质上,export default就是输出一个叫做 default 的变量或方法,然后系统允许你为它取任意名字。所以它后面不能跟变量声明语句。

// 正确
export const a = 1;

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

// 错误
export default const a = 1;

命名冲突&模块对象

可以使用关键字asexportimport进行重命名解决命名冲突

// in square.mjs
export {
  name as squareName,
  draw as drawSquare,
};

// in circle.mjs
export { name, draw };

// in main.mjs
import { squareName, drawSquare } from '/js-examples/modules/renaming/modules/square.mjs';
import {
  name as circleName,
  draw  as drawCircle } from '/js-examples/modules/renaming/modules/circle.mjs';

可以使用关键字*导入整个模块,通过模块调用导出的变量或函数

import * as Module from '/modules/module.mjs';

Module.function1();
Module.function2();

Dynamic Import

上面介绍的import语句可以导入其它模块export的变量,这是一种静态导入,是在代码初始化的时候全部导入。 出于性能的考虑在某些场景下我们需要做按需加载或延迟加载,ECMA 的动态导入方案可以满足这种场景。

import()函数可以在代码执行加载的模块返回一个 Promise 对象实例,这是我们就可以使用.then()或者await语法获取模块内容。

(async () => {
  if (somethingIsTrue) {
    const { default: myDefault, foo, bar } = await import('/modules/my-module.js');
  }
})();

TODO:NodeJS 中使用 ESM

TODO:ESM import 是否是地址引用,export 是否是有状态的

TODO:import-maps

Node.js 会自动从node_modules目录中去加载对应的模块, 但是浏览器默认不会这样做,因为不知道从哪里加载全局模块。import-maps就是为了解决浏览器中的全局模块而出现的.

设计目的:简化打包工具,将大部分功能都改造为使用浏览器原生提供能力是一种趋势


<script type="importmap">
{
  "imports": {
    "moment": "/node_modules/moment/src/moment.js",
    "lodash": "/node_modules/lodash-es/lodash.js"
  }
}
</script>

<script>
  import moment from "/node_modules/moment/src/moment.js";
  import { partition } from "/node_modules/lodash-es/lodash.js";
</script>

浅谈 import-maps

参考

results matching ""

    No results matching ""