Nodejs 中的多种导入与导出

说明

在 JavaScript 中,可以自定义模块,模块可以导出,在需要引用的地方进行导入。
在 NodeJs 中,内置的模块都遵循 CommonJS 规范,导出语法为:module.exports、exports(助记:exports 末尾有s)。
在 TypeScript 中,有 export、export default 等导出方式(助记:export 末尾没有s)。

CommonJs 中的导入与导出

导出语法为:module.exports、exports(助记:exports 末尾有s)。
可以使用 require 进行导入。

案例

定义 maths.js

function absolute(num:number){
 if (num<0) return num * (-1);
 return num;
}
module.exports = {
 pi:3.14,
 squareTwo: 1.41,
 phi: 1.61,
 absolute
}

function absolute(num:number){
 if (num<0) return num * (-1);
 return num;
}
exports.absolute = absolute;

function absolute(num:number){
 if (num<0) return num * (-1);
 return num;
}
exports = {
 pi:3.14,
 squareTwo: 1.41,
 phi: 1.61,
 absolute
}

其他

module.exports = function () {}
exports.site = 'https://www.baidu.com' 
module.exports.name = 'tomcat'

定义引用文件 main.js,使用第一种 maths.js 文件。

const maths = require('./maths');
console.log(maths.pi);

说明

很容易能够看出,模块导出时,是将要导出的对象绑定到 exports 上。
在引入的时候,require 引入了 exports 对象,定义一个变量,就可以操作该对象了。
模块中的 exports 变量指向 module.exports 。

ES Modules 中的导入与导出

在 ECMAScript 6 中,又新增了语法 export、export default(助记:export 末尾没有 s)。
常见使用如下所示。

export default function () {}
export const site = 'https://www.baidu.com' 
export const name = 'tomcat'

想要清晰的了解 es module 中的各种 export 导出方式,可以从编译后的角度来看。编译后,都是 CommonJS 的形式,很容易理解。
下面用 TypeScript 的案例,使用 tsc 进行编译,查看编译后的内容,来分析各种 export 、import 。

export default 和 export

定义 Calculator.ts

export default class Calculator {
    public add(num1, num2) {
        return num1 + num2;
    }
}
export class greet {
    public hello() {
        console.log("Hello,World!");
    }
}
export class shopping {
    public buyTv() {
        console.log("I want to buy a tv.");
    }
}

编译后 Calculator.js

"use strict";
exports.__esModule = true;
exports.shopping = exports.greet = void 0;
var Calculator = /** @class */ (function () {
    function Calculator() {
    }
    Calculator.prototype.add = function (num1, num2) {
        return num1 + num2;
    };
    return Calculator;
}());
exports["default"] = Calculator;
var greet = /** @class */ (function () {
    function greet() {
    }
    greet.prototype.hello = function () {
        console.log("Hello,World!");
    };
    return greet;
}());
exports.greet = greet;
var shopping = /** @class */ (function () {
    function shopping() {
    }
    shopping.prototype.buyTv = function () {
        console.log("I want to buy a tv.");
    };
    return shopping;
}());
exports.shopping = shopping;

引入 MyMain.ts

import MyCal, {greet, shopping} from './Calculator';
let calc = new MyCal();
console.log(calc.add(1, 2));
let myGreet = new greet();
myGreet.hello();
let myShopping = new shopping();
myShopping.buyTv();

编译后 MyMain.js

"use strict";
exports.__esModule = true;
var Calculator_1 = require("./Calculator");
var calc = new Calculator_1["default"]();
console.log(calc.add(1, 2));
var myGreet = new Calculator_1.greet();
myGreet.hello();
var myShopping = new Calculator_1.shopping();
myShopping.buyTv();

可以看到,在 Calculator.ts 中定义的类(方法也类似),如果使用 export default 方式导出,就会被挂载到 module.exports 对象的 "default" 属性对象上,因此最多只能有一个 export default 方式导出的对象,可以有多个 export 方式导出的对象;
如果使用 export 方式导出,就会被直接挂载到 module.exports 对象上,属性名是各个被挂载的类或方法名。

使用 export default 方式导出的类或方法的定义,可以使用任意的名称接收:

export default function helloWorld (){
console.log ('Hello,World');
}
import hello from './hello'

因为编译后,定义的任意名称,都会被转换成直接读取 exports["default"] 对象属性。

使用 export 方式导出的类或方法的定义,可以使用解构的方式接收:

export var pi = 3.14;
export let squareTwo = 1.41;
export const phi = 1.61;
export class RandomNumberGenerator{}
export function absolute(num:number){
 if (num<0) return num * (-1);
 return num;
}
import {pi,phi,absolute} from './maths';

使用别名

export default 方式导出时,使用别名引入:

import * as MyCalAlias from './Calculator';
let ma = new MyCalAlias.default();
ma.add(1,2);

export 导出模块时,使用解构的方式引入,可以自定义别名引入:

import {greet as nGreet, shopping as nShopping} from './Calculator';
let nGreetObj = new nGreet();
nGreetObj.hello();
let nShoppingObj = new nShopping();
nShoppingObj.buyTv();

编译后的结果

var MyCalAlias = require("./Calculator");
var ma = new MyCalAlias["default"]();
ma.add(1, 2);
var Calculator_2 = require("./Calculator");
var nGreetObj = new Calculator_2.greet();
nGreetObj.hello();
var nShoppingObj = new Calculator_2.shopping();
nShoppingObj.buyTv();

可以看到,使用 export default 方式导出后,使用别名引入时,别名操作的是 module.exports 中的 default 属性;
使用 export 方式导出后,使用别名引入时,别名操作的是 module.exports 中对应的对象。

export var pi = 3.14;
export default class RandomNumberGenerator{}
// 解构中指定别名
import {pi as p} from './maths';
// 其中解构部分为非default,非解构部分为 export default
import {pi as p},RNGen from './maths';
const rnGen = new RNGen();
// 全局指定别名
import * as math from './maths';
console.log(math.pi);
const rnGen = new math.default();

TypeScript 特定的 ES 模块语法

有些 ES 模块语法,是 TypeScript 特有的。
自定义类型的导入、导出
在 TypeScript 中,可以导出、导入自定义的类型。

animals.ts
export type Cat{
 breed: string,
 yearOfBirth: number
}
export interface Dog{
 breed: string,
 yearOfBirth: number
}
export const createCatName = () => "littleCat";

导入类型 main.ts

import type { Cat, Dog } from './animals';
import { type Cat, type Dog, createCatName } from './animals';
type Animals = Cat | Dog;

TypeScript 与 require

TypeScript 有 ES-MODULES 这样的语法,它直接可以与 CommonJS 和 amd 的 require 相关联,

使用 ES-MODULES 的 import ,在大多数情况下,和这些环境的 require 是相同的。
这种语法保证,在 TypeScript 文件中,与 CommonJS 输出有一对一的匹配。

import fs = require("fs");
const code = fs.readFileSync ("hello.ts","utf8");

其他语法

除了上面常用的导入、导出语法,还有一些其他的语法形式。
const ... = require('./module') 与 import ... from './module'
这两种形式,最终编译后的结果是一样的。
例如:

const myData = require('./module');
import myData = require('./module');

最终会转换成 var myData = require('./module')。

export=

定义 IndividualModule.ts

export = class DirectGoal {
    public goal() {
        console.log("我有一个目标!");
    }
}

在一个模块中,只能有一个 export = ,因为如果有多个,则会覆盖 module.exports 对象。
引入

import MyGoal = require('./IndividualModule');
let myGoal = new MyGoal();
myGoal.goal();

编译后

var MyGoal = require("./IndividualModule");
var myGoal = new MyGoal();
myGoal.goal();

作用与 module.exports = class DirectGoal {} 一致。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,084评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,623评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,450评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,322评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,370评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,274评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,126评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,980评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,414评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,599评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,773评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,470评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,080评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,713评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,852评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,865评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,689评论 2 354

推荐阅读更多精彩内容