[Node] Node.js JavaScrpt模块化开发

简介: [Node] Node.js JavaScrpt模块化开发

1 认识模块化

什么是模块化?

模块化开发最终的目的是将程序划分成一个个小的结构;


这个结构中编写属于 自己的逻辑代码 有自己的作用域 定义变量名称时不会影响到其他的结构


这个结构可以将自己希望暴露的变量 函数 对象 等导出给其他 结构使用


也可以通过某种方式 导入 另外结构中的变量 函数对象 等


上面提到的结构 就是模块 按照这种结构划分开发程序的过程 就是模块化开发的过程

2 CommonJS和Node

CommonJS规范和Node关系

CommonJS是一个规范 可以简称为CJS


Node是CommonJS在服务器端一个具有代表性的实现


Borowserify是CommonJS在浏览器中的一种实现


webpack打包工具 具备对CommonJS的支持和转换


Node中对CommonJS进行了支持和实现  在Node中每一个js文件都是一个单独的模块 在这个模块中包括CommonJS规范的核心变量:exports.exports require 我们可以使用这些变量来方便进行模块化开发


exports和module.exports可以负责对模块中的内容进行导出;


require函数 可以帮助我们导入其他模块(自定义模块 系统模块 第三方模块)中的内容

exports导出

exports是一个对象 可以给对象添加很多个属性 添加的属性可以被导出

JavaScript
exports.name = name;
exports.age = age;
exports.sayHello = sayHello

另一个文件导入:

JavaScript
const bar = require('./bar')

main中的bar变量等于 exports对象


也就是 require通过各种查找方式 最终找到了exports对象


并且将这根exports对象赋值给了bar变量;


bar变量就是exports对象.

module.exports 导出

在Node中我们经常导出东西的时候,又是通过module.exports导出的:


module.exports和exports有什么关系或者区别呢?


CommonJS中没有module.exports的概念的;


为了实现模块的导出,Node中使用的是Module的类,每一个模块都是Module的一个实例,也就是module;


在Node中真正用于导出的其实 根本不是exports 而是module.exports


module才是导出的真正实现者.

为什么exports也可以导出?

module对象的exports属性是exports对象的一个引用.

3 require函数解析

require细节

require是一个函数,帮助我们引入一个文件(模块)中导出对象


require的查找规则:


导入格式如下:require(X)


情况一:X是一个Node核心模块 如 path http


直接返回核心模块 且停止查找

JavaScript
// 2 导入node提供的内置模块
// require('内置模块的名称')
const path = require('path')
const http = require('path')
console.log(path,http);

情况二:X是以./或../ 或/ (根目录)开头的


1:将X当做一个文件在对应的目录下查找:


1.1 如果有后缀名,按照后缀名的格式查找对应的文件


1.2 如果没有后缀名,会按照如下顺序:


1.2.1 直接查找文件X


1.2.1 查找X.js文件


1.2.1 查找X.json文件


1.2.1 查找X.node文件

JavaScript
const foo = require('./foo')

2:没有找到对应的文件,将X作为一个目录


2.1 查找目录下面的index文件


2.1.1 查找X/index.js文件


2.1.2 查找X/index.json文件


2.1.3 查找X/index.node文件


如果都没有找到就报错! Not found


情况三:直接是一个X(没有路径),并且X不是一个核心模块

模块的加载工程

结论一:模块在被第一次引入时,模块中的js代码会被运行一次

结论二:模块被多次引入时,会缓存,最终只加载(运行)一次

为什么只会加载运行一次呢?


因为每个模块对象module都有一个属性loaded


为false表示没加载 true表示已加载


结论三:如果有循环引入 那么加载顺序是什么?

8ca2fb861cc941368b24fe2f300a79d1.png

Node采用的是深度优先算法:main=>aaa=>ccc=>ddd=>eee=>bbb

CommonJS规范缺点:

CommonJS加载模块是同步的:


只有等到对应的模块加载完毕,当前模块中的内容才能被运行


在服务器中不会有什么问题,因为服务器 加载的js文件都是本地文件 加载速度非常快


将它应用于浏览器中?


浏览器加载js文件需要先从服务器将文件下载下来,之后 再加载运行


采用同步的就意味着后续的js代码都无法正常运行,即便是一些简单的DOM操作


在浏览器中,通常不使用CommonJS规范

4 ESModule用法详解

export关键字

将一个模块中的变量 函数 类等导出


有三种方式将内容导出:


方式一:在语句声明的前面直接加上export关键字

JavaScript
export const name = 'zb'
export const age = 18

方式二:将所有需要导出的标识符,放到export后面的{}中


这里的{}里面不是ES6的对象字面量的增强写法,{}也不是表示一个对象的


所以:export{name:name} 是错误的写法

JavaScript
export {
    name,
    age,
    sayHello
}

方式三:导出时 给表示符起一个别名


通过as关键字起别名

JavaScript
export {
     name as fname,
     age,
     sayHello
 }

import关键字

import关键字负责从另外一个模块中导入内容


导入内容的方式:


方式一:importi{标识符列表} from '模块';


注: 这里的{}不是一个对象,里面只是存放导入的标识符列表内容

JavaScript
import {name,age,sayHello} from "./foo.js"

方式二:导入时给标识符起别名


通过as关键字起别名

JavaScript
import {name as fname ,age,sayHello} from "./foo.js"

方式三: 通过 * 将模块功能放到一个模块功能对象(a module object)上

JavaScript
导入时 可以给整个模块起别名
import * as foo from "./foo.js"

export和import结合使用(相对高级写法)

补充:export和import可以结合使用

JavaScript
export { formatCount,formatDate } from './format.js'

为什么曜这样做呢


在开发和封装一个一个功能库时 希望将暴露的所有接口放到一个文件中


方便指定统一的接口规范 也方便阅读


我们就可以使用export和import结合使用

default用法

导出功能的都是 有名字的导出(named exports):


在导出export时指定了名字


在导入import时需要知道具体的名字


一种导出叫 默认导出(default export)


默认导出export时 不需要指定名字


在 导入时 不需要使用{} 并且可以自己来指定名字


它也方便我们和现有的CommonJS等规范相互操作


注:在一个模块中 只能有一个默认导出(default export)

import函数

通过import加载一个模块 是不可以在其放到逻辑代码中的 如:

JavaScript
// // 在导入的时候 必须放到顶层
import {name,age,sayHello} from "./foo.js"
JavaScript
// 不允许在逻辑代码中编写import 是不允许这样做的
let flag = true
if(flag){
    import {name,age,sayHello} from "./foo.js"
    console.log(name,age);
}

在某些情况下,确实希望动态的来加载某个模块


这个时候 我们就需要使用import()函数来动态加载


import函数返回一个Promise,可以通过then获取结果

JavaScript
let flag = true
if(flag){
    // 如果确实是逻辑成立时 才需要导入某个模块
    // import函数
    const importPromise = import("./foo.js")
    importPromise.then(res=>{
        console.log(res);
    })
    console.log("================");
}

   但是上面这种写法 又比较麻烦,真实开发中是这样写的

JavaScript
let flag = true
if(flag){
    import("./foo.js").then(res=>{
        console.log(res);
    })
    console.log("================");
}

为什么会出现这个情况?


因为ES Module在被JS引擎解析时 就必须知道它的依赖关系.


由于这个时候js代码没有任何的运行,所以无法进行类似于if判断中根据代码的执行情况.


甚至 拼接路径的写法也是错误的,因为我们必须到运行时能确定path值

(扩展)import meta

import.meta是一个给JavaScript模块暴露特定上下文的元数据属性的对象


它包含了这个模块的信息,如这个模块的URL


在ES11 (ES2020)中新增的特性

5 ESModule运行原理

ES Module的解析流程

ES Module的解析过程可以划分为三个阶段:


一:构建(Constuction),根据地址查找js文件并下载,将其解析成模块记录(Module Record)


二:实例化(Instantiation),对模块记录进行实例化,并分配内存空间,解析模块的导入和导出语句,把模块指向对应的内存地址


三:运行(Evaluation)运行代码,计算值.并且将值填充到内存地址中


阶段一:构建过程

a054c3955e3341cd8842ff29e28d3d96.png

阶段二:实例化阶段 求值阶段

afd2e12ee245499386cabb0ce3b84dec.png

相关文章
|
10月前
|
Web App开发 JavaScript 前端开发
Node.js 是一种基于 Chrome V8 引擎的后端开发技术,以其高效、灵活著称。本文将介绍 Node.js 的基础概念
Node.js 是一种基于 Chrome V8 引擎的后端开发技术,以其高效、灵活著称。本文将介绍 Node.js 的基础概念,包括事件驱动、单线程模型和模块系统;探讨其安装配置、核心模块使用、实战应用如搭建 Web 服务器、文件操作及实时通信;分析项目结构与开发流程,讨论其优势与挑战,并通过案例展示 Node.js 在实际项目中的应用,旨在帮助开发者更好地掌握这一强大工具。
268 1
|
5月前
|
存储 JavaScript 前端开发
在NodeJS中使用npm包进行JS代码的混淆加密
总的来说,使用“javascript-obfuscator”包可以帮助我们在Node.js中轻松地混淆JavaScript代码。通过合理的配置,我们可以使混淆后的代码更难以理解,从而提高代码的保密性。
402 9
|
9月前
|
存储 JavaScript NoSQL
Node.js新作《循序渐进Node.js企业级开发实践》简介
《循序渐进Node.js企业级开发实践》由清华大学出版社出版,基于Node.js 22.3.0编写,包含26个实战案例和43个上机练习,旨在帮助读者从基础到进阶全面掌握Node.js技术,适用于初学者、进阶开发者及全栈工程师。
144 9
|
10月前
|
JSON JavaScript 前端开发
使用JavaScript和Node.js构建简单的RESTful API
使用JavaScript和Node.js构建简单的RESTful API
|
10月前
|
开发框架 JavaScript 前端开发
Node.js日记:客户端和服务端介绍、Node.js介绍
Node.js日记:客户端和服务端介绍、Node.js介绍
|
前端开发
windows10 安装node npm 等前端环境 并配置国内源
windows10 安装node npm 等前端环境 并配置国内源
683 3
|
SQL JavaScript 数据库
sqlite在Windows环境下安装、使用、node.js连接
sqlite在Windows环境下安装、使用、node.js连接
|
JavaScript 前端开发 Shell
mac和windows上安装nvm管理node版本
NVM(Node Version Manager)是前端开发者常用的命令行工具,用于管理计算机上的不同Node.js版本。通过NVM,开发者可以轻松地在多个项目间切换所需的Node.js版本。在Mac上,可以通过cURL或Wget下载安装脚本,或使用包管理工具brew安装。安装后需配置环境变量以识别NVM命令。Windows用户则可通过专用的nvm-windows安装程序完成安装。常用命令包括安装、卸载特定版本、列出已安装版本等。
|
JavaScript Windows
记一下 Windows11 安装与配置 node.js 的标准步骤
这篇文章记录了在Windows 11系统上安装和配置Node.js的步骤,包括安装Node.js、验证安装、配置npm、设置npm镜像加速、全局安装cnpm并配置镜像、解决TLS连接不安全警告的详细过程。
1430 0