Node.js开发、CommondJS 、ES-Module模块化设计

news2024/9/22 5:39:27

目录

 Node.js是什么

基础使用

Node的REPL

全局变量

 模块化设计

CommondJS规范

 基础使用exports和module.exports

require

 CommondJS优缺点

AMD和CMD规范

ES_Module

 基本使用方法

导出

导入

 结合使用

默认导出

ES Module解析流程


 Node.js是什么

 Node与浏览器的对比

 在浏览器中,HTML与CSS交给Blink处理,如果其发现了JS代码,就会交给V8处理

而Node是直接V8处理JS代码,Node主要由JS(api)、C++和C语言编写,libuv主要绑定js与操作系统的操作

下载地址

Node.js

基础使用

可以在VScode中的终端使用node

console.log(1123123);
console.log('asdada');

在终端中直接  node XXX.js(XXX是文件名,在运行时终端的文件域必须和该文件一致)

  如果要从终端输入参数

console.log(1123123);
console.log('asdada');

console.log(process.argv);

结果:

1123123
asdada
[
  'C:\\Program Files\\nodejs\\node.exe',
  'C:\\Users\\12860\\Desktop\\品优购项目\\test.js',
  'num1=123'
]

也就是说  process.argv输出的是一个数组,你输入的数据在数组的第3个之后  

Node的REPL

 

在控制台输入node,可以一行一行输入并执行js代码

 用的很少

全局变量

例如global,类似于window

console.log(global);

可以看到js中的全局变量

<ref *1> Object [global] {
  global: [Circular *1],
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  structuredClone: [Function: structuredClone],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  atob: [Function: atob],
  btoa: [Function: btoa],
  performance: Performance {
    nodeTiming: PerformanceNodeTiming {
      name: 'node',
      entryType: 'node',
      startTime: 0,
      duration: 33.55670002102852,
      nodeStart: 2.157499998807907,
      v8Start: 4.655900001525879,
      bootstrapComplete: 23.560699999332428,
      environment: 13.318800002336502,
      loopStart: -1,
      loopExit: -1,
      idleTime: 0
    },
    timeOrigin: 1668353099915.782
  },
  fetch: [AsyncFunction: fetch]
}

对于浏览器来说有window,对于node来说有global,所以创造了一个总的全局变量,在两个地方都能用,叫globalthis 

 模块化设计

解释一下第二点

对于之前的做法,如果我有很多js文件,第一个文件aaa.js定义了var name = 111

第二个文件bbb.js定义var name = 222

当我在第三个js文件通过scrip src方式引入这两个js文件时,这个name变量就会变得模糊

而模块化设计的要求是,不同模块的变量是不会互相影响的,且外部无法访问

但是肯定不希望所有的变量,外部都不能访问,所有可以通过一些方法导出自己希望外部能访问的内容,既第三点

 立即执行函数可以解决变量冲突的问题,如果在aaa.js和bbb.js中的代码都放入立即执行函数中,由于函数本身就有作用域,所以不会互相影响

但是如果外部想调用变量,就必须确定立即执行函数的返回对象,这会增加使用难度

CommondJS规范

 基础使用exports和module.exports

在test.js里面写

const name = 'lmx'
const age= 18
const fn = function(){
    console.log(123);
}
exports.name = name 
exports.age = age
exports.fn = fn

 在mian.js写

const test = require('./test.js')
console.log(test);
console.log(test.name);
test.fn()

必须要用node运行main.js

其实本质就是引用赋值

test.js创建了exports对象,然后往里面写入元素name age fn,但是exports变量保留的是该对象的地址

而require也是获取的对象的地址,所以两者指向的是同一个对象

那么在test.js里面改变值,也会影响到main.js

例如,test.js:

const name = 'lmx'
const age= 18
const fn = function(){
    console.log(123);
}
exports.name = name 
exports.age = age
exports.fn = fn

setTimeout(()=>{
    exports.name  = 'qweqwe' 
},2000)

main.js

const test = require('./test.js')
console.log(test);
console.log(test.name);
test.fn()
setTimeout(()=>{
    console.log(test.name);
},2500)

{ name: 'lmx', age: 18, fn: [Function: fn] }
lmx
123
qweqwe

但是上述方法在开发中使用的很少,一般用module.exports

将test.js中的exprots改为:

const name = 'qwe'
const age = 17

module.exports.name = name
module.exports.age = age

main.js不需要改

看上去还变复杂了,从本质上来说,这种方法会创造一个module对象,该对象里面包含了一个exports,指向之前创造的对象

所以说这里左边的exports和module.exports其实是一个东西,因为指向的是同一个对象

在require的时候,其实node本质上拿到的是module.exports,但是因为module.exports===exports,所有现在看来两种方式是一样的

 真实开发做法是

const name = 'qwe'
const age = 17
console.log(age);

module.exports={
    name,
    age
}
exports.name = 'hhhhh'

 本质是,这里会创造一个新的对象,module.exports指向这个对象,那么这个对象跟之前的exports对象就没有关系了

使用require获取的也是这个新的对象,所有改exports.name没有意义了

结果是{ name: 'qwe', age: 17 }

require

例如,内置模块包含了很多方法

const test = require('path')
console.log(test);
<ref *1> {
  resolve: [Function: resolve],
  normalize: [Function: normalize],
  isAbsolute: [Function: isAbsolute],
  join: [Function: join],
  relative: [Function: relative],
  toNamespacedPath: [Function: toNamespacedPath],
  dirname: [Function: dirname],
  basename: [Function: basename],
  extname: [Function: extname],
  format: [Function: bound _format],
  parse: [Function: parse],
  sep: '\\',
  delimiter: ';',
  win32: [Circular *1],
  posix: <ref *2> {
    resolve: [Function: resolve],
    normalize: [Function: normalize],
    isAbsolute: [Function: isAbsolute],
    join: [Function: join],
    relative: [Function: relative],
    toNamespacedPath: [Function: toNamespacedPath],
    dirname: [Function: dirname],
    basename: [Function: basename],
    extname: [Function: extname],
    format: [Function: bound _format],
    parse: [Function: parse],
    sep: '/',
    delimiter: ':',
    win32: [Circular *1],
    posix: [Circular *2],
    _makeLong: [Function: toNamespacedPath]
  },
  _makeLong: [Function: toNamespacedPath]
}

 意思是有的时候可以省略.js等

第三种情况,X即不是内置模块,也不是文件,例如

const test = require('why')

它会找上层文件夹中下的node_modules文件夹,这个文件夹名字是固定的,然后再在node_modules文件夹里面找why文件夹,再找why文件夹下的index.js

如果没找到node_modules,就返回再上一层文件夹接着找,直到找到或者找到根目录为止

所以在npm install axios的时候,其实就是创建了一个node_modules文件夹,把axios相关的文件放进去了

 CommondJS优缺点

AMD和CMD规范

 已经用的很少了,做一个了解吧

 

ES_Module

ES module是ES6新增的JS模块化的功能,如果浏览器支持ES6则可以直接使用

如果不支持,一般是通过webpack打包之后再接入浏览器

 基本使用方法

在html引入js这么写,加type = 'module',这样就可以创建独立的作用域,不会互相影响

但是在打开时,必须打开服务,例如使用live server

    <script src="./main.js" type="module"></script>
    <script src="./test.js" type="module"></script>

导出

const name = 'why'
const age =14
export{
    name,
    age
}

这个地方,export{}不是新建的一个对象,只是大括号将标识符包含起来

也可以在定义的时候直接导出

const name = 'why'
export const age =14

导入

import {name,age }from './test.js'
console.log(name );
console.log(age);

导入的时候可以起个别名

import {name as fname,age }from './test.js'
console.log(fname );
console.log(age);

导入语句只能写在顶端,不能写在逻辑代码里面 

例如

let flag = true
if(flag){
    import{name,age} from './test.js'
}

这种会直接报错

但是我就是想放在逻辑里面使用呢,比如当某种条件成立的时候才导入

可以用到import函数

let flag = true
if(flag){
    let promise1 = import('./test.js')
    promise1.then(res=>{
        console.log(res.name);
        console.log(res.age);
        res.fn()
    })
}

因为该函数是异步的,其返回值是一个promise,调用then拿到结果 

 结合使用

如果现在有很多js文件,基本上每个文件都导出了一些方法

如果index,html想得到这些方法,就得一个一个script src=

一般的做法是,再新建一个index.js,里面将那些js文件导入,再直接导出,所以在html文件中就可以直接只导入index.js

那么在index.js里面就可以这么写

export{getdata,getname} from './aaa.js'
export{getdata1,getname2} from './bbb.js'

默认导出

如果一个js文件,他的文件名就已经代表了他的功能,且只需要导出一个东西,就可以使用默认导出

const name = 'why'

export default name

 如果导出的函数,甚至可以不写函数名字

export default function(){
    console.log('asdasd');
}

很显然,一个模块只能有一个默认导出

之前的导入中 ,都需要导出和导入的变量名字保持一直(除非使用as改名),使用默认导出,就可以在导入的时候自己设置一个名字

import aaa from './test.js'
console.log(aaa);

ES Module解析流程

首先第一步,对于js文件进行下载,解析为 模块记录module record,例如如果在index.html中引入了main.js,那么会首先下载这个js文件。

如果js文件中也存在导入语句,那么跟第一步一样,先下载对应的js文件,创建模块记录,这里是会直接搜索文件的最开始部分有没有import语句,所以不能将其放入逻辑判断中。

这里还会生成一个映射表 module map,放入js文件的地址和对应的  module record,在这个图中main.js引入的counter.js,如果别的文件也引入了counter.js,那么就可以在这个表中直接拿到 module record

第二步,如果有导出语句,例如export const age = 18,那么会生成一个模块环境记录  module environment record 放置 age变量,但是它是没有值的。

值得注意的是,上述两步是没有执行一行代码的

第三步,运行,填充环境记录中的变量值,例如填充age 的值是多少,在后续别的模块import这个age的时候,就可以从这里拿到

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/12864.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

两点云求差集和交集

这里两点云的差集指从点云1中删除属于点云2的点得到的点集&#xff0c;并集指既属于点云1又属于点云2的点集。 两点云求差集 基于kd-tree搜索的方法较快速&#xff0c;当然也可以暴力搜索。思路如下&#xff1a; step1 在点云2建立kd-tree&#xff0c;设置容忍误差&#xff0…

UI控件DevExpress WinForm新手指南——如何在应用启动时执行操作

DevExpress WinForm拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForm能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜任…

RESTful 接口设计

文章目录RESTful 接口设计1.获取所有员工列表2.增加一个员工3.更新员工4.删除员工5.查询单个员工RESTful 接口设计 1.获取所有员工列表 /*** 获取所有员工* 1. 请求路径--确认资源--员工--/employees* 2. 请求方法--get* 3. 请求参数--无* 4. 请求响应--多个员工--List<Em…

苹果iOS App Store上架操作流程

很多开发者在开发完iOS APP、进行内测后&#xff0c;下一步就面临上架App Store&#xff0c;不过也有很多同学对APP上架App Store的流程不太了解&#xff0c;下面我们来说一下iOS APP上架App Store的具体流程&#xff0c;如有未涉及到的部分&#xff0c;大家可以及时咨询&#…

基于微信小程序的学生购电系统设计与实现-计算机毕业设计源码+LW文档

小程序开发说明 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Mave…

服务端Skynet(二)——消息调度机制

服务端Skynet(二)——消息调度机制 文章目录服务端Skynet(二)——消息调度机制1、提前了解知识1.1、互斥锁&#xff08;mutex lock : **mut**ual **ex**clusion lock&#xff09;1.2、自旋锁&#xff08;spinlock&#xff09;1.3、读写锁&#xff08;readers–writer lock&…

最简单的git图解(多远程仓库)

上一节我们讲了git操作最基本的命令&#xff1a;最简单的git图解&#xff08;最基本命令&#xff09;_jerry_dyy的博客-CSDN博客 这一节我们来讲一下面对多个远程仓库的场景&#xff0c;应该如何来处理。 为什么要有多个远程仓库&#xff1f; 在企业内部开发团队开发过程中&a…

什么是CDN?CDN的技术原理是什么?

什么是CDN&#xff1f; CDN的全称是Content Delivery Network&#xff0c;中文名称“内容分发网络”。其主要原理是在现有网络中增加一层新的网络架构&#xff0c;将源站中的内容发布到不同的网络节点上&#xff0c;使用户可以就近获得所需的内容&#xff0c;从而提高用户访问…

【学习记录】镭神激光雷达与PC机的NTP同步

本文仅用于记录自己在实现镭神C32激光雷达和PC机进行NTP同步时的一些总结。 吐槽在先&#xff0c;镭神的文档写极其不完善&#xff0c;很多都只是提了一句&#xff0c;但并没有完整的说应该具体怎么做。前前后后折腾了三四天&#xff0c;在一知半解的官方技术支持和实验室大佬…

立创EDA仿真入门1 基本操作

立创EDA仿真入门1 基本操作一、进入EDA仿真环境二、画原理图1. 新建工程2. 绘制如下电路图三、仿真1. 运行仿真2. 导出波形图3. 查看仪表一、进入EDA仿真环境 网址&#xff1a; https://lceda.cn/ 进入EDA标准版&#xff0c;点击左上角切换到仿真模式。 二、画原理图 1. 新…

java毕业设计——基于java+Socket+sqlserver的办公自动化系统设计与实现(毕业论文+程序源码)——办公自动化系统

基于javaSocketsqlserver的办公自动化系统设计与实现&#xff08;毕业论文程序源码&#xff09; 大家好&#xff0c;今天给大家介绍基于javaSocketsqlserver的办公自动化系统设计与实现&#xff0c;文章末尾附有本毕业设计的论文和源码下载地址哦。 文章目录&#xff1a; 基于…

qemu创建linux虚拟机(亲测有效)

1&#xff0c;网桥的搭建 Bridge方式原理 Bridge方式即虚拟网桥的网络连接方式&#xff0c;是客户机和子网里面的机器能够互相通信。可以使虚拟机成为网络中具有独立IP的主机。 桥接网络&#xff08;也叫物理设备共享&#xff09;被用作把一个物理设备复制到一台虚拟机。网桥多…

【语义分割】数据增强方法(原图与标签同时扩增)

1、数据增强作用 避免过拟合 提升模型的鲁棒性 提高模型的泛化能力 避免样本不均衡的问题 2.、数据增强分类 可分为两类&#xff1a;在线增强和离线增强。这两者的区别在于离线增强是在训练前对数据集进行处理&#xff0c;往往能得到多倍的数据集&#xff0c;在线增强是在训练…

javaEE高阶---Spring 更简单的读取和存储对象

一 : 引言 经过前面的学习&#xff0c;我们已经可以实现基本的 Spring 读取和存储对象的操作了&#xff0c;但在操作的过程中我们发现读取和存储对象并没有想象中的那么“简单”&#xff0c;所以接下来我们要学习更加简单的操作 Bean 对象的方法 . 二 : 存储Bean对象 2.1 使…

【Hack The Box】windows练习-- Reel

HTB 学习笔记 【Hack The Box】windows练习-- Reel &#x1f525;系列专栏&#xff1a;Hack The Box &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2022年11月17日&#x1f334; &#x1f3…

视频清晰度优化指南

一、背景介绍 随着移动互联网的深入发展&#xff0c;视频消费场景逐渐变成主流&#xff0c;早期由于手机硬件的限制问题&#xff0c;导致生产出来的视频画质、清晰度存在较大的问题&#xff0c;用户体验不太好&#xff0c;当时的网络也处于4G的发展阶段&#xff0c;网络的限制…

【Hack The Box】windows练习-- support

HTB 学习笔记 【Hack The Box】windows练习-- support &#x1f525;系列专栏&#xff1a;Hack The Box &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2022年11月17日&#x1f334; &#x…

策略验证_买入口诀_双管齐下买进不怕

写在前面&#xff1a; 1. 本文中提到的“股票策略校验工具”的具体使用操作请查看该博文&#xff1b; 2. 文中知识内容来自书籍《同花顺炒股软件从入门到精通》 3. 本系列文章是用来学习技法&#xff0c;文中所得内容都仅仅只是作为演示功能使用 目录 解说 策略代码 结果 解…

【正点原子FPGA连载】 第一章 MPSoC简介 摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第一章 MPSoC简介…

【Loadrunner】学习loadrunner——Controller与Analysis的使用(三)

文章目录1.controller的使用1.1.创建场景的方式1.2.页面的介绍1.3.场景的设置1.2.1.设置初始化1.2.2.设置启动机制1.2.3.设置性能测试脚本的执行时间1.2.4.设置虚拟用户推出机制1.3.场景的运行1.4.场景的运行方式1.4.1.按照场景的方式运行1.4.2.按照group运行2.analysis的使用2…