目录

微信小程序开发系列-14模块的导入与导出

微信小程序开发系列-14模块的导入与导出

微信小程序开发系列目录

文章目录

前言

对于初学者可能对CommonJS和ESmodules两种规范的导入导出的使用有点儿混淆,另外微信小程序官方文档写得只支持Common JS,一来是想理清两种导入导出方式,二来是想实际验证下微信小程序是否两种规范都支持。于是探索的过程便形成了此文。

什么是CommonJS

CommonJS是一种JavaScript语言的模块化规范,主要用于服务端的Node.js环境。每个文件在CommonJS中都被视为一个模块,具有独立的作用域、变量和方法,对其他模块不可见。模块通过 module.exports 暴露其公共接口,其他文件则通过 require() 方法来加载这个模块。CommonJS的主要目的是让各种模块能够在各个服务器环境中得到支持,并实现类似于本地文件模块系统一样的功能。CommonJS从原始设计上就是考虑到服务器端JavaScript,不适合客户端(这就是引入ES模块的原因)。

什么是ES modules

ES Modules(ESM)是ECMAScript的官方模块系统,也被称为ECMAScript Modules或简称ES Modules。它是JavaScript中用于模块化开发的新规范,也是ECMAScript 6(ES6)标准的一部分。

ES Modules引入了一种新的、官方的模块系统,以解决以前在JavaScript中模块化开发中存在的一些问题。它允许动态地导入和导出模块,提供了一种官方的模块化解决方案,促进了代码的模块化和复用。

与CommonJS等其他模块系统相比,ES Modules具有一些优势,例如静态导入和导出、静态模块结构、更好的异步支持、更强的类型检查等。主流的浏览器和Node.js环境都已支持ES Modules,开发者可以使用export和import语句来导入和导出模块,并在script标签中设置type=“module"来使用模块内容。

ES modules

模块导出

在创建 JavaScript 模块时, export 语句用于从模块中导出实时绑定的函数、对象或原始值,以便其他程序可以通过 import 语句使用它们。被导出的绑定值依然可以在本地进行修改。在使用 import 进行导入时,这些绑定值只能被导入模块所读取,但在 export 导出模块中对这些绑定值进行修改,所修改的值也会实时地更新。

存在两种 exports 导出方式:

  1. 命名导出(每个模块可包含任意数量)
  2. 默认导出(每个模块仅包含一个)
// 导出单个特性
export let name1, name2, , nameN; // also var, const
export let name1 = , name2 = , , nameN; // also var, const
export function FunctionName(){...}
export class ClassName {...}

// 导出列表
export { name1, name2, , nameN };

// 重命名导出
export { variable1 as name1, variable2 as name2, , nameN };

// 解构导出并重命名
export const { name1, name2: bar } = o;

// 默认导出
export default expression;
export default function () {  } // also class, function*
export default function name1() {  } // also class, function*
export { name1 as default,  };

// 导出模块合集
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 ;

因此,对于ESModules 模块导出,是通过 export语句 来进行模块导出。

模块导入

静态 import 语句 用于导入由另一个模块导出的绑定。

import statement

import defaultExport from "module-name";
import * as name from "module-name";
import { export1 } from "module-name";
import { export1 as alias1 } from "module-name";
import { default as alias } from "module-name";
import { export1, export2 } from "module-name";
import { export1, export2 as alias2, /* … */ } from "module-name";
import { "string name" as alias } from "module-name";
import defaultExport, { export1, /* … */ } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";

import()

The import() syntax, commonly called dynamic import , is a function-like expression that allows loading an ECMAScript module asynchronously and dynamically into a potentially non-module environment.

语法:

import(moduleName)

The import() call is a syntax that closely resembles a function call, but import itself is a keyword, not a function . You cannot alias it like const myImport = import , which will throw a SyntaxError .

标准用法的 import 导入的模块是静态的,会使所有被导入的模块,在加载时就被编译(无法做到按需编译,降低首页加载速度)。有些场景中,你可能希望根据条件导入模块或者按需导入模块,这时你可以使用动态导入代替静态导入。

下面的是可能会需要动态导入的场景:

  • 当静态导入的模块很明显的降低了代码的加载速度且被使用的可能性很低,或者并不需要马上使用它。
  • 当静态导入的模块很明显的占用了大量系统内存且被使用的可能性很低。
  • 当被导入的模块,在加载时并不存在,需要异步获取。
  • 当导入模块的说明符,需要动态构建。(静态导入只能使用静态说明符)
  • 当被导入的模块有副作用(这里说的副作用,可以理解为模块中会直接运行的代码),这些副作用只有在触发了某些条件才被需要时。(原则上来说,模块不能有副作用,但是很多时候,你无法控制你所依赖的模块的内容)
import("/modules/my-module.js").then((module) => {
  // Do something with the module.
});

学习完了理论,接下来,看看在微信小程序中,基于ESModules,进行导入导出的实验。

示例

本示例实现一个简单的加法运算,加法函数放在common.js中导出,然后在mod.js中导入并使用。

<!--mod/mod.wxml-->
<view class="container">  
  <view>数字1:</view>  
  <input type="number" placeholder="输入数字" bindinput="onInput1" />  
  <view>+</view>  
  <view>数字2:</view>  
  <input type="number" placeholder="输入数字" bindinput="onInput2" />  
  <button bindtap="onTapButton">计算</button>  
  <view>结果: {{result}}</view>  
</view>
/* mod/mod.wxss */
.container {  
  display: flex;  
  flex-direction: column;  
  align-items: center;  
}  
input {  
  width: 80%;  
  margin-bottom: 10px;  
}  
button {  
  width: 80%;  
}  
view {  
  margin-bottom: 10px;  
}
// common.js
function add(a,b){
  return (a + b);
}
function sub(a,b){
  return (a - b);
}

export {add, sub};
// mod/mod.js
import {add,sub} from './common'
Page({
  data: {
    num1: 0,
    num2: 0,
    result: 0,
  },
  onInput1: function(e) {  
    this.setData({ num1: e.detail.value });  
  },  
  onInput2: function(e) {  
    this.setData({ num2: e.detail.value });  
  },  
  onTapButton: function() {  
    let result = add(Number(this.data.num1), Number(this.data.num2));
    this.setData({ result: result });  
  },  
})

https://i-blog.csdnimg.cn/blog_migrate/12a9f6c7348a1ed076f1de3b953363f1.png

从上图的运行结果来看,导入导出是奏效的。接下来,再看看import()导入是否work。

https://i-blog.csdnimg.cn/blog_migrate/ff1ee02603b96e43507b913f80116e47.png

Congratulations!动态导入也是奏效的。

CommonJS

CommonJS模块规范是Node.js中用于处理模块的标准。

模块导入

require(id)

  • id : module name or path
  • Returns: exported module content

Used to import modules, JSON , and local files. Modules can be imported from node_modules . Local modules and JSON files can be imported using a relative path (e.g. ./ , ./foo , ./bar/baz , ../foo ) that will be resolved against the directory named by (if defined) or the current working directory.

模块导出

Modules.exports 是一个对象 。

The module.exports object is created by the Module system. Sometimes this is not acceptable; many want their module to be an instance of some class. To do this, assign the desired export object to module.exports . Assigning the desired object to exports will simply rebind the local exports variable, which is probably not what is desired.

关于exports,它是一个变量,只是为了更简洁地书写而存在。 module.exports.f = ... 更简洁的书写成 exports.f = ... ,但是,请注意,与任何变量一样,如果将新值分配给 exports ,则它不再绑定到 module.exports 。一般不建议用这种。

The exports variable is available within a module’s file-level scope, and is assigned the value of module.exports before the module is evaluated.

下面一段伪代码可以很好地解释不建议使用 exports 的原因:

function require(/* ... */) {
  const module = { exports: {} }; // default object
  ((module, exports) => {
    // Module code here. In this example, define a function.
    function someFunc() {};
    exports = someFunc;
    // At this point, exports is no longer a shortcut to module.exports, and
    // this module will still export an empty default object.
    module.exports = someFunc;
    // At this point, the module will now export someFunc, instead of the
    // default object.
  })(module, module.exports);
  return module.exports;
}

示例

这是示例的逻辑和上一节相同,只是将导入和导出用法改成了CommonJS的规范。

https://i-blog.csdnimg.cn/blog_migrate/fa64b76e4330d137fe8ccad35edf2e91.png

总结

通过本文的学习,掌握了在微信小程序中的模块的导入导出 既可以使用ES modules标准,也可以使用CommonJS标准。我个人更倾向于ES标准,模块的可移植性更好些。