学习ECMAScript 2015【11】Modules

0.背景

  本文的主角是 Modules 。你会问:“必须模块化吗?可是经理让我一分钟后上线!”

学习ECMAScript 2015【11】Modules

1.总览

  其实写Vue项目的时候,很多时候都用到了模块化编程,常常写export import,好,我们先简要浏览一下:

// lib/math.js
export function sum(x, y) {
  return x + y;
}
export var pi = 3.141593;
// app.js
import * as math from "lib/math";
console.log("2π = " + math.sum(math.pi, math.pi));
// otherApp.js
import {sum, pi} from "lib/math";
console.log("2π = " + sum(pi, pi));
// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
    return Math.exp(x);
}
// app.js
import exp, {pi, e} from "lib/mathplusplus";
console.log("e^π = " + exp(pi));

2.分开谈谈

  正如MDN所说的,Javascript 程序本来很小——在早期,它们大多被用来执行独立的脚本任务,在你的 web 页面需要的地方提供一定交互,所以一般不需要多大的脚本。

  过了几年,我们现在有了运行大量 Javascript 脚本的复杂程序,还有一些被用在其他环境(例如 Node.js)。使用JavaScript 模块依赖于importexport

2.1.export

  export可以用来导出函数、对象、值等等,

  比如我们导出一些变量,比如环境配置的URL、一个Web请求函数、一个写好的工具类等等。

// Exporting individual features
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function functionName(){...}
export class ClassName {...}

  同样的,我们还可以导出列表、重命名变量、解构已有的对象进行导出:

// Export list
export { name1, name2, …, nameN };

// Renaming exports
export { variable1 as name1, variable2 as name2, …, nameN };

// Exporting destructured assignments with renaming
export const { name1, name2: bar } = o;

  一个要学会的重点是default的使用,它帮助我们在js文件末尾输出唯一一个导出的东西。与多个export相比,这么确实要友好一点。

export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };

  还记得function*是什么吗?之前说过哦,是生成器,讲过的哦。

学习ECMAScript 2015【11】Modules

  举一个例子,在开源项目newbee-mall-vue3-app
中,对axios进行封装,添加一些诸如默认的头部信息后,最后导出封装好的axios对象供其它模块使用。

...
axios.interceptors.response.use(res => {
  if (typeof res.data !== 'object') {
    ElMessage.error('服务端异常!')
    return Promise.reject(res)
  }
  if (res.data.resultCode != 200) {
    if (res.data.message) ElMessage.error(res.data.message)
    if (res.data.resultCode == 419) {
      router.push({ path: '/login' })
    }
    return Promise.reject(res.data)
  }

  return res.data.data
})

export default axios

  当然,在一些情况下,你也可以聚合模块,视具体需要使用即可。

// Aggregating modules
export * from …; // does not set the default export
export * as name1 from …; // Draft ECMAScript® 2O21
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export { default, … } from …;

2.2.import

  开局先来一个 Call Back! 还记得之前说过的默认导出的写法吧,导入的时候就可以使用这种写法对应:

import defaultExport from "module-name";

  然后需要注意的是,如果导入一个模块中所有的内容,记得对这个模块来个命名,因为导入N个模块,模块之间肯定有重名的变量。这相当于给它们加了一个命名空间的感觉。

import * as name from "module-name";

  最常见的用法是用上解构,从模块导出的多个属性中抽出来一个,像这样:

import {myExport} from '/modules/my-module.js';

聊点番外,这一段参考的MDN上的英文对应的文字是这样的:

Given an object or value named myExport which has been exported from the module my-module either implicitly (because the entire module is exported, for example using export * from ‘another.js’) or explicitly (using the export statement), this inserts myExport into the current scope.

里面提到了两个单词explicitly(明确地)implicitly(暗含的),一个向外ex,一个向内im,这一对单词频繁出现。如果你在思考代码的复用和设计,要常常思考什么应该隐含其中而什么应该明确指明,这种分寸感,只能在特定的不同的情景下反复尝试才能找到。

  另外,多个直接加逗号就可以,如果在导出的时候发现原有导出的内容十分简易、容易重复,也可以重命名。

import {
  reallyReallyLongModuleExportName as shortName,
  anotherLongModuleName as short
} from '/modules/my-module.js';

  有时候,你会直接import一个js文件,就是为了让这个js文件做一些初始化的工作,比如帮你创建个文件目录之类的。

import '/modules/my-module.js';

  这里稍微聊一下动态导入,这部分我还真没看到谁经常使用,其实就是,如果嫌弃静态导入拖慢了载入速度,或者是遇到了导入什么js之后必须执行什么(我是没遇到过),这类的特殊场景会使用。

3.结语

  好了,模块化是大势所趋,各个语言的未来,希望大家多多思考如何封装代码,让代码简洁、高效且安全稳定。祝愿读到这里的你没有bug。

上一篇:程序与用户交互,基本运算符


下一篇:stream使用