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 {} 一致。

你可能感兴趣的:(Nodejs 中的多种导入与导出)