JS模块化-ES Module

124 阅读2分钟

导出

// 单个单出
export const ADMIN_LIST = [
    'user_01', 'user_02', 'user_03'
];
// 单个导出
export function addAdmin(nick){
    ADMIN_LIST.push(nick);
    return ADMIN_LIST;
}

// 默认导出
export default function getUserByNick(nick){
    const map = {
        'user_01': {nick: 'user_01', name: 'JS'},
        'user_02': {nick: 'user_02', name: 'CSS'},
        'user_03': {nick: 'user_03', name: 'HTML'},
    }
    return map[nick] ? map[nick] : null;
}

单个导出还可以这样写

const ADMIN_LIST = [
    'user_01', 'user_02', 'user_03'
];

function addAdmin(nick){
    ADMIN_LIST.push(nick);
    return ADMIN_LIST;
}

export {
    ADMIN_LIST,
    addAdmin
}

导入

注意:导入时也必须明确文件扩展名

// 此时默认导出getUserByNick需要在第一位
import getUserByNick, { ADMIN_LIST, addAdmin } from './es-1.js';

默认导入还可以这样写:

import {default as getUserByNick} from './es-1.js';

NodeJS 支持

使用

说明:代码的运行环境为node v12.22.12 Xnip2022-05-15_15-26-58.jpg

1)增加package.json,并声明type module

Xnip2022-05-15_15-30-46.jpg

2)文件扩展名改为.mjs

Xnip2022-05-15_15-34-05.jpg

版本

  • 2017-09-26 v8.6.0 支持mjs,执行时需要 --experimental-modules标志
  • 2020-05-26 v12.17.0 去掉 --experimental-modules 标志

演示

  • v8.5.0 Xnip2022-05-17_09-13-16.jpg

  • v10 Xnip2022-05-16_08-55-34.jpg

  • v12.17 Xnip2022-05-16_08-52-46.jpg

浏览器支持

Xnip2022-05-16_21-23-23.jpg

Xnip2022-05-16_21-20-59.jpg

Xnip2022-05-16_21-21-58.jpg

特点

1、多次导入只会执行一次
es-1.mjs

console.log('execute es-1.js');

export const ADMIN_LIST = [
    'user_01', 'user_02', 'user_03'
];

es-2.mjs

import { ADMIN_LIST } from './es-1.mjs';
import { ADMIN_LIST as ADMINS } from './es-1.mjs';

console.log('ADMIN_LIST ', ADMIN_LIST);
console.log('ADMINS ', ADMINS);

Xnip2022-05-16_09-06-43.jpg

2、import和export是静态的

  • import是在编译阶段执行,在代码运行之前
    es-1.mjs

    console.log('execute es-1.js\n');
    
    export const ADMIN_LIST = [
        'user_01', 'user_02', 'user_03'
    ];
    

    es-2.mjs

    console.log('execute es-2.js\n');
    import { ADMIN_LIST } from './es-1.mjs';
    
    console.log('ADMIN_LIST ', ADMIN_LIST);
    

    导入的模块会先运行 Xnip2022-05-16_09-14-07.jpg

  • import和export只能放在顶层,不能在块级作用域中。不能条件导出/入 Xnip2022-05-16_20-58-08.jpg

3、导入的是值的引用
es-1.mjs

export const ADMIN_LIST = [
    'user_01', 'user_02', 'user_03'
];

export function addAdmin(nick){
    ADMIN_LIST.push(nick);
    return ADMIN_LIST;
}

es-2.mjs

import { ADMIN_LIST, addAdmin } from './es-1.mjs';
console.log('admin list is ' + ADMIN_LIST);

addAdmin('user_04');
console.log('\nadmin list is ' + ADMIN_LIST);

Xnip2022-05-16_09-23-16.jpg

4、导入的变量是只读的

Xnip2022-05-16_21-03-21.jpg

动态导入

语法import('filePath'),返回一个promise。
需要运行环境支持顶级await (top level await),node是从v14.3开始支持的(此版本运行时需要增加参数 --experimental_top_level_await)。
es-1.mjs

async function getAdminList(){
    return new Promise((resolve, reject) => {
        setTimeout(() =>{
            resolve(['user_01', 'user_02', 'user_03']);
        }, 1000);
    });
}

export const ADMIN_LIST = await getAdminList();

es-2.mjs

console.time('before import');

const moduleExport = await import('./es-1.mjs');
console.log(moduleExport.ADMIN_LIST)

console.timeEnd('before import');

Xnip2022-05-16_08-47-33.jpg

注意:import() 看起来像是函数调用,但实际是语法

加载commonJS模块

ES Module 的import可以正常加载commonjs的模块

es-1.cjs

exports.hi = function(nick){
    console.log('hi ' + nick);
}

es-2.mjs

import es2 from './es-1.cjs';

console.log(es2);

es2.hi('amyli');

Xnip2022-05-17_08-42-39.jpg

还可以单个导入

import { hi } from './es-1.cjs';

console.log(hi);

hi('amyli');

但如果CommonJS模块是用module.exports整体导出的,import 也只能整体导入

Xnip2022-05-17_08-46-56.jpg