[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

相关文章
|
Web App开发 JavaScript 前端开发
Node.js 是一种基于 Chrome V8 引擎的后端开发技术,以其高效、灵活著称。本文将介绍 Node.js 的基础概念
Node.js 是一种基于 Chrome V8 引擎的后端开发技术,以其高效、灵活著称。本文将介绍 Node.js 的基础概念,包括事件驱动、单线程模型和模块系统;探讨其安装配置、核心模块使用、实战应用如搭建 Web 服务器、文件操作及实时通信;分析项目结构与开发流程,讨论其优势与挑战,并通过案例展示 Node.js 在实际项目中的应用,旨在帮助开发者更好地掌握这一强大工具。
726 1
|
JavaScript 前端开发 安全
【逆向】Python 调用 JS 代码实战:使用 pyexecjs 与 Node.js 无缝衔接
本文介绍了如何使用 Python 的轻量级库 `pyexecjs` 调用 JavaScript 代码,并结合 Node.js 实现完整的执行流程。内容涵盖环境搭建、基本使用、常见问题解决方案及爬虫逆向分析中的实战技巧,帮助开发者在 Python 中高效处理 JS 逻辑。
|
存储 JavaScript 前端开发
在NodeJS中使用npm包进行JS代码的混淆加密
总的来说,使用“javascript-obfuscator”包可以帮助我们在Node.js中轻松地混淆JavaScript代码。通过合理的配置,我们可以使混淆后的代码更难以理解,从而提高代码的保密性。
1669 9
|
存储 JavaScript NoSQL
Node.js新作《循序渐进Node.js企业级开发实践》简介
《循序渐进Node.js企业级开发实践》由清华大学出版社出版,基于Node.js 22.3.0编写,包含26个实战案例和43个上机练习,旨在帮助读者从基础到进阶全面掌握Node.js技术,适用于初学者、进阶开发者及全栈工程师。
521 9
|
JSON JavaScript 前端开发
使用JavaScript和Node.js构建简单的RESTful API
使用JavaScript和Node.js构建简单的RESTful API
|
负载均衡 JavaScript 前端开发
为什么要用 Node.js
这是一个移动端工程师涉足前端和后端开发的学习笔记,如有错误或理解不到位的地方,万望指正。 Node.js 是什么 传统意义上的 JavaScript 运行在浏览器上,这是因为浏览器内核实际上分为两个部分:渲染引擎和 JavaScript 引擎。前者负责渲染 HTML + CSS,后者则负责运行 JavaScript。Chrome 使用的 JavaScript 引擎是 V8,
2467 0
|
JavaScript Unix Linux
nvm与node.js的安装指南
通过以上步骤,你可以在各种操作系统上成功安装NVM和Node.js,从而在不同的项目中灵活切换Node.js版本。这种灵活性对于管理不同项目的环境依赖而言是非常重要的。
4198 11
|
存储 JavaScript 搜索推荐
Node框架的安装和配置方法
安装 Node 框架是进行 Node 开发的第一步,通过正确的安装和配置,可以为后续的开发工作提供良好的基础。在安装过程中,需要仔细阅读相关文档和提示,遇到问题及时解决,以确保安装顺利完成。
1390 155
|
弹性计算 JavaScript 前端开发
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
Node.js 是一种高效的 JavaScript 运行环境,基于 Chrome V8 引擎,支持在服务器端运行 JavaScript 代码。本文介绍如何在阿里云上一键部署 Node.js 环境,无需繁琐配置,轻松上手。前提条件包括 ECS 实例运行中且操作系统为 CentOS、Ubuntu 等。功能特点为一键安装和稳定性好,支持常用 LTS 版本。安装步骤简单:登录阿里云控制台,选择扩展程序管理页面,安装 Node.js 扩展,选择实例和版本,等待创建完成并验证安装成功。通过阿里云的公共扩展,初学者和经验丰富的开发者都能快速进入开发状态,开启高效开发之旅。