美文网首页
Node中的模块使用

Node中的模块使用

作者: 薯条你哪里跑 | 来源:发表于2021-08-02 18:07 被阅读0次

1.概述

node默认使用的是commonjs模块规范。每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

如果要共享只能挂在全局变量global上(不推荐这种做法ヽ(`Д´)ノ):

global.plat = “PC”;

或者通过模块引用的方式(推荐(๑•̀ㅂ•́)و✧):。

CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

2. 加载

CommonJS使用require来引入模块,使用exportsmodule.exports来导出模块(module);

const { read, write } = require('./file');

CommonJS只能在运行时才能确定模块的引用及依赖关系。上述代码其实是先加载file这个整个对象,之后再取上面的属性。

const file = require('./file');
const read  =   file.read
const write  =   file.write

ps: 但是es6是通过export命令直接导出,在编译时就可以判断要加载的方法即我们所说的静态编译。为后续的类型校验和宏提供了可能

3.module

Node内部有个Module的构造函数,每个文件中的module都是其的一个实例,module有以下几个属性:

  • id 模块的识别符,通常是带有绝对路径的模块文件名。
  • path 模块的路径,模块文件对应的路径。
  • exports 表示模块对外输出的值。
  • parent 返回一个对象,表示调用该模块的模块,也是Module的一个实例。
  • filename 模块的文件名,带有绝对路径。
  • loaded 返回一个布尔值,表示模块是否已经完成加载。
  • children 返回一个数组,表示该模块要用到的其他模块。
  • paths 返回一个数组,表示模块的搜索路径。
随便找个文件,打印一下console.log(module)
Module {
  id: '/Users/pub/f-node-encryption/dist/index.js',
  path: '/Users/pub/f-node-encryption/dist',
  exports: {},
  parent: Module {
    id: '.',
    path: '/Users/pub/f-node-encryption/test',
    exports: {},
    parent: null,
    filename: '/Users/pub/f-node-encryption/test/index.js',
    loaded: false,
    children: [ [Circular] ],
    paths: [
      '/Users/pubf-node-encryption/test/node_modules',
      '/Users/pub/f-node-encryption/node_modules',
      '/Users/pub/node_modules',
      '/Users/node_modules',
      '/node_modules'
    ]
  },
  filename: '/Users/pub/f-node-encryption/dist/index.js',
  loaded: false,
  children: [
    Module {
      id: '/Users/pub/f-node-encryption/dist/src/lib/util.js',
      path: '/Users/pub/f-node-encryption/dist/src/lib',
      exports: [Object],
      parent: [Circular],
      filename: '/Users/pub/f-node-encryption/dist/src/lib/util.js',
      loaded: true,
      children: [Array],
      paths: [Array]
    }
  ],
  paths: [
    '/Users/pub/f-node-encryption/dist/node_modules',
    '/Users/pub/f-node-encryption/node_modules',
    '/Users/pub/node_modules',
    '/Users/node_modules',
    '/node_modules'
  ]
}

node引用模块很简单,在文件内部使用exportsmodule.exports来导出。举个🌰

// a.js  定义一个TestClass类
class TestClass {
  constructor(){}
  .....
}
 module.exports = TestClass

// b.js 引用并实例化
const  TestClass = require("./a")
cosnt curTest =  new  TestClass()
....
console.log(exports===module.exports)  // 输出true

这里使用module.exports来进行导出,当然也可以使用 exports, 但是!!!我们不能直接给 exports赋值,像这样:

exports = TestClass

这是不可以的!!!因为使用的exports其实是module.exports的引用,如果直接赋值会使引用断开,此时在b.js内打印TestClass会输出module.exports的值,此时就是一个空对象。

再次重申,模块导出导出的是module.exports的值!!!

当然在保留引用的前提下可以进行赋值:

// a,js
exports.test = TestClass

// b.js 
const  TestClass = require("./a")
cosnt curTest =  new  (TestClass.test)()

4. CommonJS模块的特点。

主要有以下三点:

  • 所有代码都运行在模块作用域,不会污染全局作用域。
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存(delete require.cache[moduleName])。
  • 模块加载的顺序,按照其在代码中出现的顺序。
关于第二条还想仔细说一下

举个缓存的🌰:

// a.js
var tmp = {name::“Jack”};
module.exports = tmp; 

// b.js
const OnceTest = require("./a")
// 输出OnceTest为 {name:“Jack”}
console.log("OnceTest:", OnceTest) 
// 给 OnceTest添加新的属性
OnceTest.age = 21;   
// 再次引入相同模块
const TwiceTest = require("./a")
// 此时打印TwiceTest,发现里面也有age属性
console.log("TwiceTest:", TwiceTest)  // 输出{name:“Jack”, age:21} 

如果我想清除缓存那么需要修改下b.js:

const OnceTest = require("./a")
console.log("OnceTest:", OnceTest) 
OnceTest.age = 21;   
// 先要清除引入模块的缓存
delete require.cache['/Users/pub/f-node-encryption/a.js']
// 再次引入相同模块
const TwiceTest = require("./a")
// 此时打印TwiceTest,发现已经是从a.js新引入的模块了
console.log("TwiceTest:", TwiceTest)  // 输出{name:“Jack”} 

详细cache里的内容可以打印require.cache查看。
这里贴一个清除缓存时存在的问题 传送门

4.顺便记一下ES中的模块使用

在ES中的模块使用相对灵活,使用export export detault来导出,使用import来引用。

我们先看一下exportexport default这两个导出方式有什么不同

  • 在一个文件中,export可以有多个但export default只能有一个。
  • 通过export方式导出,在导入时要加{ },export default则不需要。
  • export能直接导出变量表达式,export default不行。
// 导出变量
export const a = 123;
// 导出方法
export const getName = function(){}
// 导出方法
function getName(){}
export {getName}

// excport default 导出变量
const a = 123;
export default a
// 导入
// 使用 export 方法导出
import { dogSay, catSay } from './test'; 
// 使用export default导出
import a from './test';  
// as 集合成对象导出
import * as testModule from './test'; //as 集合成对象导出

其他细节不再次赘述啦,感兴趣的小伙伴自行学习;
还有一点需要注意一下,因为import是静态解析的,所以在引入前使用也是不会报错的:

dogSay()
import { dogSay, catSay } from './test';

但是 不可以在这样“动态”使用import

const  moduleName = "dog"
import { `${moduleName}Say` } from './test';
// 或者这样
if(moduleName === "dog"){
  import { dogSay`} from './test';
}

写的有点凌乱回头在整理一波= =

相关文章

  • 无标题文章

    node模块与包管理 在Node中,使用的是Commonjs模块标准,commonjs模块系统是文件之间共享对象或...

  • 01-Node 基础使用

    Node 基础使用Node 介绍Node 模块化开发模块成员的导出模块成员的导入Node 系统模块 path 和 ...

  • 深入解析node.js的模块加载机制

    在node.js中,模块使用CommonJS规范,一个文件是一个模块 node.js中的模块可分为三类 内部模块 ...

  • 浅析node.js的模块加载逻辑

    module 在node.js中,模块使用CommonJS规范,一个文件是一个模块 node.js中的模块可分为三...

  • Node中的模块使用

    1.概述 node默认使用的是commonjs模块规范。每个文件就是一个模块,有自己的作用域。在一个文件里面定义的...

  • node.js笔记1

    Node.js、使用vscode搭建js环境、nodejs中的模块、http协议 Node.js Node.js平...

  • 2018-08-20第五天课

    内置模块 => 直接使用 Node 提供好的核心模块 Event 事件模块事件模块是整个 Node.js ...

  • EventEmitter

    Node的事件模块中,目前只包含一个类:EventEmitter。这个类在Node的内置模块中被大量使用,在Nod...

  • Node-核心模块(fs、path)

    一、核心模块fs 1、文件读取 使用 Node 中 提供的 文件操作API,读取指定 文件中的文本内容 Node ...

  • nodejs-报表(xlsx)

    1.node-excel node-excel作为node.js模块导出数据到Excel xlsx文件中。在使用n...

网友评论

      本文标题:Node中的模块使用

      本文链接:https://www.haomeiwen.com/subject/jdhfvltx.html