JS模块的艺术

本文详细介绍了ES6的模块语法,包括export和import的基本用法,as和*的语法特性,以及模块组织形式的扩展,如单文件双模式导出和多文件索引。通过实例解析了模块导出和导入的编译过程,帮助读者掌握模块化编程的关键知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ES6的module导出引入总结。

基本module语法

  ES6提供了exportimport语法,给予了JS模块化代码组织形式的能力。export语句用于从模块中导出函数、对象或原始值,以便其他程序可以通过import语句使用它们。

export

  我们假设我们拥有一个fileA.js的文件,它向外export了这些:

// fileA.js
export const DEMO_VALUE = '123';
export function demoFunction(param) { console.log(param); }
export default 123

  export有两种导出形式。一种是使用export语句接上const/let/var/function等声明变量函数的语句向模块外导出值。一个文件内部可以存在多个export语句。另一种是使用export default直接加上值(不接声明语句)的方式向模块外导出值。一个文件内部只能存在一个export default语句。

  我们用babel来看一下实际上export实际转化成了什么。

// export const DEMO_VALUE = '123';
// export default 123
// babel transform
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.DEMO_VALUE = void 0;
var DEMO_VALUE = '123';
exports.DEMO_VALUE = DEMO_VALUE;
var _default = 123;
exports.default = _default;

  babel使用了类似于commonJS的模块导入导出规则(nodeJS的模块规则),对export语句进行编译。首先声明了一个exports的对象,它拥有__esModuletrue的一个标。接着使用exports.变量名/函数名的方式,把所有export声明的值添加到exports对象上。随后添加export default的值到exportsdefault上。按照上面的例子,我们在该模块会得到下面这个对象:

{
    __esModule: true,
    DEMO_VALUE: '123',
    default: 123,
}

import

  现在我们新建一个fileB.js文件,使用import来引入这些fileA.js向外暴露的值。import也有两种导入值的语法:

// fileB.js
import demoA /* 你要的变量值 */ from 'fileA.js';
import { DEMO_VALUE } from 'fileA.js';

  第一种语法是直接使用import + 任意变量名 from 文件路径。该方法能够导入fileA.js中使用export default暴露的内容。你必须保证导入的文件名拥有
export default向外暴露的内容,否则将会产生错误,我们来看一下babel对其的编译:

// import demoA from 'fileA.js';
var _fileA = _interopRequireDefault(require("fileA.js"));

function _interopRequireDefault(obj) {
    return
        obj
        &&
        (obj.__esModule ? obj : { default: obj });
}

  这边首先声明了一个名为_interopRequireDefault的函数,用这个函数来处理require 文件进来的值。_interopRequireDefault函数对引入的对象做了一个简单判断,如果带有__esModule的标志的,说明是使用export语法编译过的导出内容,直接返回obj,否则应该是commonJS导入规则,从obj中解构default重命名为obj,然后返回。

  import第二种导入语法是导入export暴露的内容。前面说过,一个模块可以使用多个export进行声明的导出。因此此时引入这些值,需要名称对应。即你export const a; export const b;,在引入时候就需要import { a, b } from '文件',名称a必须要对应。

as 和 * 语法

  当模块的提供方和使用方不是同一个人的时候,exportimport需要对其声明名称时,有可能会产生一个问题,我使用export向外暴露的一些变量名称你已经使用过了,此时你又不方便去修改node_modules当中的源码去修改一个变量名称,你可以使用as语法来重命名一个import进来的模块。

// fileA.js
export const DEMO_VALUE = '123';
// fileB.js
import { DEMO_VALUE as FILEA_DEMO } from './fileA.js';

  你还可以使用*语法来导出一个模块的全部导出,这样在使用模块内多方法函数的时候,能够清晰模块的调用。

// fileA.js
export function returnName(name) { return name; }
export function returnAgePulsOne(age) { return age + 1; }
// fileB.js
import * as utils from './fileA.js';
utils.returnName('123'); // '123'
utils.returnAgePulsOne(2); // 3

基于模块组织形式的一些语法扩充

  在日常的工作中,实际上还有更多模块化的使用场景和需求。

单文件双模式导出

  诸如像React之类的公共库,拥有主模块和很多副模块方法。实际上可以提供exportexport default双模式来方便使用者的引入。在写React库的时候,我们经常会出现这些使用场景。

// 仅仅 JSX
import React from 'react';
// Component
import { Component } from 'react';
// 实际上你还可以这样
import React, { Component } from 'react';

  能够使用React, { Component }这种语法,是因为React向外提供了export以及export default两种模式的导出声明。我们来举一个简单的例子:

// fileA.js
export function formateDate() {}
export function getNowDate() {}
export default {
    formateDate,
    getNowDate,
};

// fileB.js
import utils, { formateDate } from 'fileA.js';
console.log(utils); // { formateDate, getNowDate }

多文件索引

  在ES6的module语法中,当你在文件路径当中/文件夹,确没有指定文件目录的时候,会自动去查找文件夹下的index.js。在很多多方法多模块的库中,使用index.js文件作为索引来暴露出所有方法的模式是十分常见的。

  我们来举一个实际的场景,我现在在一个项目文件中,拥有一个utils的文件夹,存放项目中所有方法类函数,比如像上面的处理date的一些方法函数,以及一些ajax请求函数。我的目录层级场景大概是这样的:

// /utils文件夹
// /utils/service.js 用于存放ajax一些方法
export function ajaxPost(url, data) {}
export function ajaxGet(url, query) {}
// /utils/date.js date处理的一些方法
function formateDate() {}
function getNowDate() {}
export default { formateDate, getNowDate }

  我现在需要在utils文件夹下面,新建一个index.js的文件,来把我utils文件夹下所有其它js文件的方法全部暴露出去,让外部引用的时候,只需要import { something } from 'utils'即可,而不用继续往下去找到下一层的js文件。此时我们就需要联合exportfrom,来把一个模块直接引用暴露出去。

// /utils/index.js
export { ajaxPost, ajaxGet } from './service.js';
export { default as dateUtils } from './date.js';

  我们关注一下date.js这个文件。该文件是通过export default来暴露出一个对象,储存了所有的处理函数。这里由于index.js是使用export from的方式来直接导出引入的声明,所以我们需要对date.js文件的引用进行一个命名。我们前面看过使用export default暴露出去的值实际上是作为default暴露出去的,所以这里是可以通过as语法来修改default的名称来达到修改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值