JavaScript模块化开发

news2024/10/6 6:44:04

目录:

1 认识模块化开发

2 CommonJS和Node

3 require函数解析

4 AMD和CMD(了解)

5 ESModule用法详解

6 ESModule运行原理

模块化不是两个不同的js文件直接导入到某个页面中的,因为这两个文件只要有相同的变量或函数,两个js文件导入到某个页面的时候变量和函数都会出现冲突、覆盖。

 真正的模块化就是4点:

早期是没有模块化开发的,解决办法是使用 '立即执行函数'(因为变量放在函数里面,函数有自己的作用域,这个变量名和其他函数里面的没有任何关系,不冲突)

使用 '立即执行函数' 有个缺点就是拿不到函数里面的变量,解决办法是把变量return出去。其他页面拿变量的方法就是 立即执行函数的名称.变量名称。

由于使用 '立即执行函数'缺点是在js文件里面的立即执行函数的数量多且名称都不一样,很混乱。

怎么使用common.js规范?

1、在浏览器中默认是不能使用export的。在vue中可以是因为webpack打包。

2、在node执行js文件是可以使用export的,node有集成common.js

common.js在node里面实现的原理就是引用赋值。就是说export导出的是一个对象,导出的是对象在内存中的地址,require导入的也就是变量的地址了,不管是导出的文件修改值还是导入的文件修改值都会使得变量的值在内存中的值改变。

在开发的时候常用的写法是module.exports = {  xxx:xxx , yyy:yyy } 这里xxx和yyy可以使用增强写法module.exports = {  xxx , yyy }

module.exports={}的写法与exports.xxx=xxx 和module.exports.xxx=xxx 的不同之处是module.exports={}会在内存中新开辟一个地址来存储变量,也就是原来的文件里面的变量发生改变也不会改变这里的变量值,exports.xxx=xxx 和module.exports.xxx=xxx引用的是原来的内存地址。

举个例子:

exports.xxx=xxx 和module.exports.xxx=xxx指向的是下图的0*100的地址,

module.exports = {  xxx:xxx , yyy:yyy }指向的是0*200的地址

const name = "foo"
const age = 18
function sayHello() {
  console.log("sayHello")
}

// 1.在开发中使用的很少
// exports.name = name
// exports.age = age
// exports.sayHello = sayHello

// 2.将模块中内容导出
// 结论: Node导出的本质是在导出module.exports对象
// module.exports.name = name
// module.exports.age = age
// module.exports.sayHello = sayHello

// // console.log(exports.name, "----")
// // console.log(exports.age, "----")
// // console.log(exports.sayHello, "----")
// console.log(exports === module.exports)

// 3.开发中常见的写法
module.exports = {
  name,
  age,
  sayHello
}

// exports.name = "哈哈哈哈"
// module.exports.name = "哈哈哈哈"

require是有自己的查找规则的:

1、(会自动加后缀)会先找文件,再去找文件夹,然后在找json文件,再再再找node文件

2、会去核心模块查找

3、会到当前文件夹的node_modules里面查找,如果没有就会去上层目录去找node_modules文件夹

// 1.根据路径导入自己编写模块
// const utils = require("./utils")
// console.log(utils.formatDate())

// const foo = require("./foo")


// 2.导入node提供给内置模块
// const path = require("path")
// const http = require("http")
// console.log(path, http)


// 3.情况三: 名称不是路径, 也不是一个内置模块
// const why = require("why")
// console.log(why)

// const axios = require("axios")
// console.log(axios)

console.log(this)

common.js  模块的加载过程:

1、模块在被第一次引入时,模块中的js代码会被运行一次

2、模块被多次引入时,会缓存,最终只加载(运行)一次

3、如果模块里面需要导入其他模块,在运行的时候会以深度遍历的情况把最里层需要导入的文件先运行完。如下图的引用模块的顺序是:main -> aaa -> ccc -> ddd -> eee ->bbb

commonjs的缺点:

在浏览器中运行是会影响很大,因为是同步的,在模块中的需求模块没被记载完成之前,外层的代码都不会执行。但是在webpack里面就不会出现这种情况,因为项目打包之后会把所有这些模块代码打包到一个js文件里面(如果没有分包操作)。

以前在webpack里面模块化主要是commonjs。在浏览器中是amd和cmd,现在这两个已经没有使用了。

ES Module:

目前可以通过esmodule或者commonjs实现模块化。两者的区别是esmodule需要浏览器支持才能用。webpack是打包出来变成普通的js文件,基本上大多数地方都可以直接用。

默认是严格模式的。

esmodule的import导入的文件名字必须写全,不像commonjs一样可以省略后缀(因为commonjs会自动添加后缀),

ES Module的使用方法:

页面导入需要的js文件 <script src="xxx" type="module"></script>

不能直接通过打开页面文件的方式来打开,会出现跨域的错误,这个时候需要通过vscode右键打开菜单选择在一个服务上运行才不会报跨域。

通过直接打开这个页面(对应vscode的 Open In Default Browser): 

通过服务打开这个页面(对应vscode的 Open With Live Server): 

 foo.js代码:

const name = "why"
const age = 18

function sayHello() {
  console.log("sayHello")
}

// 导出 export 这里不是用了对象增强的写法,这里的name就是变量名称
export {
  name,
  age,
  sayHello
}

main.js代码:

// 导入 import
// 注意事项一: 在浏览器中直接使用esmodule时, 必须在文件后加上后缀名.js
import { name, age, sayHello } from "./foo.js"

// const name = "main"

console.log(name)
console.log(age)
sayHello()

ES Module的导出导出方式有三种:

1、普通导出,导入的时候名称必须和导出的名称相同

2、导出时给个别变量取别名

3、直接在创建变量的时候导出变量

// 3.导出方式三:
export const name = "why"
export const age = 18

export function sayHello() {
  console.log("sayHello")
}

export class Person {}

// console.log(name)

// 1.导出方式一: 
// export {
//   name,
//   age,
//   sayHello
// }

// 2.导出方式二: 导出时给标识符起一个别名
// export {
//   name as fname,
//   age,
//   sayHello
// }

// 1.导入方式一: 
// import { name, age, sayHello } from "./foo.js"

// 2.导入方式二: 导入时给标识符起别名
// import { name as fname, age, sayHello } from "./foo.js"

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

const name = "main"

console.log(name)
console.log(foo.name)
console.log(foo.age)
foo.sayHello()

export和import结合使用:

这种情况应用的场景是  模块文件夹里面有很多模块,我们会创建一个index.js的文件来当做入口文件,在index.js文件里面写入 模块文件夹里面所有模块导出的内容。在之后的某个文件需要使用时就直接去index.js引用就可以了。

写法:export {xxx} from "xxxx"  

 

format.js和parse.js是模块化的文件,utils是模块文件夹,index.js是入口文件,main.js是导入入口文件的文件

format.js代码:

export function formatCount() {
  return "200万"
}

export function formatDate() {
  return "2022-11-11"
}

parse.js代码:

export function parseLyric(lyricString) {
  return ["歌词"]
}

 index.js代码:

import { formatCount, formatDate } from './format.js'
import { parseLyric } from './parse.js'

// export {
//  formatCount,
//  formatDate,
//  parseLyric
// }

// 优化一: (常用的)
// export { formatCount, formatDate } from './format.js'
// export { parseLyric } from './parse.js'

// 优化二: (优点是方便快速导出所有导出的内容)
//(缺点是不知道引入的内容有什么,需要回到文件去查看导出了什么)
// export * from './format.js'
// export * from './parse.js'

main.js代码:

// import { formatCount, formatDate } from "./utils/format.js"
// import { parseLyric } from "./utils/parse.js"

import { 
  formatCount, 
  formatDate, 
  parseLyric 
} from './utils/index.js'

console.log(formatCount())
console.log(formatDate())

console.log(parseLyric())

页面导入main.js文件:

 

默认导出   export default

注意:在一个模块中,只能有一个默认导出(default export),导入时可以任意给名称。

parse_lyric.js是默认导出的文件,main.js是导入模块的文件。

 parse_lyric.js代码:

// 1.默认的导出:
// // 1.1. 定义函数
// function parseLyric() {
//   return ["歌词"]
// }

// const name = "aaaa"

// // export {
// //   parseLyric,
// //   name
// // }

// 1.2.默认导出
// export default parseLyric


// 2.定义标识符直接作为默认导出
export default function() {
  return ["新歌词"]
}

// export default function() {
//   return ["歌词"]
// }

// 注意事项: 一个模块只能有一个默认导出

main.js代码:

// import { parseLyric } from "./parse_lyric.js"

// 下面的名称parseLyric是不一定的,可以取别的名称,不会有影响,
import parseLyric from "./parse_lyric.js"

// 之后要引用的话必须和导入时的名称引用
console.log(parseLyric())

import函数的使用(是异步的):

模块的导入在文件里面是不可以放在逻辑代码里面的,只能放在文件顶部:

 但是确实有情况需要我们判断完之后才引入模块的话,我们该怎么办?(有这种需求是因为加载不必要的js文件也一样需要消耗性能,文件大了,加载时间也长;还有一种应该是做

条件判断添加路由路径的时候)

foo.js代码:

export const name = "foo"
export const age = 18

export function sayHello() {
  console.log("sayHello")
}

console.log(import.meta)

 main.js代码:

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

console.log(name, age)


// 2.import函数的使用
// let flag = true
// if (flag) {
//   // 不允许在逻辑代码中编写import导入声明语法, 只能写到js代码顶层
//   // import { name, age, sayHello } from "./foo.js" 
//   // console.log(name, age)

//   // 如果确实是逻辑成立时, 才需要导入某个模块
//   // import函数返回的是promise
//   // const importPromise = import("./foo.js")
//   // importPromise.then(res => {
//   //   console.log(res.name, res.age)
//   // })

// 下面这种是最常见的
   import("./foo.js").then(res => {
    console.log(res.name, res.age)
  })

//   console.log("------")
// }

import.meta可以获取import的url地址

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

相关文章

html学习(标签、css、选择器)

认识HTML HTML是HyperText Markup Language的缩写&#xff0c;中文名为超文本标记语言。它是一种用来创建网页的标准标记语言&#xff0c;由标签&#xff08;tag&#xff09;和文本构成&#xff0c;用于描述网页的结构和内容。HTML文档可以被浏览器解析并呈现出网页的内容和样…

方向梯度直方图(Histogram of Oriented Gradient)

1.方向梯度直方图&#xff08;Histogram of Oriented Gradient&#xff09; 笔记参考&#xff1a;HOG特征提取 笔记参考&#xff1a;一文讲解方向梯度直方图&#xff08;hog&#xff09; 笔记参考&#xff1a;Histogram of Oriented Gradients (HOG) | By Dr. Ry Stemplicity …

【Java-01】深入浅出匿名对象 , 继承 , 抽象类

主要内容 面向对象回顾 匿名对象介绍 面向对象特征 - 继承 抽象类的使用 模板设计模式 1 面向对象回顾 面向对象的核心思想是什么 ? 用代码来模拟现实生活中的事物 , 比如学生类表示学生事物 , 对象表示的就是具体的学生 , 有了类就可以描述万千世界所有的事物了 现有的…

【PaddleNLP-kie】关键信息抽取2:UIE模型做图片信息提取全流程

文章目录 本文参考UIE理论部分step0、UIEX原始模型使用网页体验本机安装使用环境安装快速开始 step1、UIEX模型微调&#xff08;小样本学习&#xff09;微调模型对比step2、服务化部署step3、提升推理速度模型量化更换模型fast-tokenizer提高batch_size&#xff08;没用&#x…

第十一章 组合模式

文章目录 前言一、组合模式基本介绍二、UML类图三、完整代码抽象类&#xff0c;所有类都继承此类学校类以父类型引用组合一个学院类学院类以父类型引用组合一个专业类专业类&#xff0c;叶子节点&#xff0c;不能再组合其他类测试类 四、组合模式在JDK集合的源码分析五、组合模…

51单片机(一)软硬件环境和单片机介绍

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其实STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

delta.io 参数 spark.databricks.delta.replaceWhere.constraintCheck.enabled

总结 默认值true 你写入的df分区字段必须全部符合覆盖条件 .option("replaceWhere", "c2 == 2") false: df1 overwrite tb1: df1中每个分区的处理逻辑: - tb1中存在(且谓词中匹配)的分区,则覆盖 - tb1中存在(谓词中不匹配)的分区,则append - tb1中不存…

热闹之后,香港是否会成为Web3的“应许之地”?

出品&#xff5c;欧科云链研究院 作者&#xff5c;Jason Jiang 自从2022年底有关虚拟资产在港发展的政策宣言发布后&#xff0c;香港始终是Web3世界的焦点。当港府官员频繁现身以鼓励Web3创新发展&#xff0c;当数以万计的Web3 Builders时隔三年再次聚首香江&#xff0c;当传…

密码学报Latex模板使用

密码学报Latex模板使用 首先从密码学报下载模板 然后注册overleaf账号 创建新项目&#xff0c;把.zip包导入 修改编译器为XeLaTeX 然后点击重新编译即可

信息安全复习六:公开密钥密码学

一、章节梗概 1.公开密钥密码模型的基本原理 2.两个算法&#xff1a;RSA&D-H算法 主要内容 1.对称密钥密码的密钥交换问题 2.公钥密码模型的提出 3.设计公钥密码的基本要求 4.数字签名 5.RSA算法 6.公钥密码的特征总结 二、对称密钥密码 对称加密算法中&#xff0c;数据…

SpringCloud --- Feign远程调用

一、RestTemplate问题 先来看我们以前利用RestTemplate发起远程调用的代码&#xff1a; 存在下面的问题&#xff1a; 代码可读性差&#xff0c;编程体验不统一参数复杂URL难以维护 Feign是一个声明式的http客户端&#xff0c;官方地址&#xff1a;GitHub - OpenFeign/feign:…

程序员如何提高代码能力

目录 程序员如何提高代码能力——C语言方向阅读优秀的代码不断练习学习新技术与他人合作不断反思和改进 程序员如何提高代码能力——C语言方向 C 是一种功能强大的编程语言&#xff0c;广泛应用于操作系统、数据库、游戏开发等领域。而要成为一名优秀的 C 程序员&#xff0c;不…

动力节点Vue笔记④ Vue与Ajax

四、Vue与AJAX 4.1 回顾发送AJAX异步请求的方式 发送AJAX异步请求的常见方式包括&#xff1a; 原生方式&#xff0c;使用浏览器内置的JS对象XMLHttpRequest const xhr new XMLHttpRequest()xhr.onreadystatechange function(){}xhr.open()xhr.send() 原生方式&#xff0…

RK3568平台开发系列讲解(调试篇)内核函数调用堆栈打印方法汇总

🚀返回专栏总目录 文章目录 一、dump_stack 函数二、WARN_ON(condition)函数三、BUG_ON (condition)函数四、panic (fmt...)函数沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将对驱动调试方法进行汇总学习。 一、dump_stack 函数 dump_stack 作用:打印内核调…

C++、STL标准模板库和泛型编程 ——迭代器、 算法、仿函数(侯捷)

C、STL标准模板库和泛型编程 ——迭代器、 算法、仿函数 &#xff08;侯捷&#xff09; 迭代器iterator_category 算法accumulatefor_eachreplacecountfindsortbinary_search 仿函数 functors(六大部件中最简单的一种&#xff01;) 使用一个东西&#xff0c;却不明白它的道理&a…

Compiler- volatile关键字

为了直观的感受编译器为程序所做的编译优化&#xff0c;我们通过以下的C程序来进行演示&#xff08;只能体现编译优化的一小部分hh~&#xff09;。 请大家预测一下下面代码的输出结果 #include <iostream>int main(void) {const volatile int local 10;int* ptr (int…

中国人民大学与加拿大女王大学金融硕士国际班——海归学子最强后援

有人脉&#xff0c;成功像坐电梯&#xff1b;没人脉&#xff0c;成功像爬楼梯。这是每一个职场人都有体悟的“潜规则”。对海归同学来说&#xff0c;加入母校校友会是结识优秀人才、迅速拓展本地人脉圈的不二法宝。中国人民大学与加拿大女王大学金融硕士国际班为海归学子提供最…

QMS-云质说质量 - 4 为什么有的质量人不属于质量部?

想管理好质量&#xff0c;首先就要把质量人员放在合适的组织架构中。 对人进行管理&#xff0c;基本原则是&#xff1a;尽量让员工的利益与企业的利益保持同步&#xff0c;虽然无法做到完全重合&#xff0c;但出发点肯定要战略一致。 俗话说“屁股决定脑袋”&#xff0c;因此&a…

【数据结构初阶】第六节.队列的实现

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、队列的初步认识 二、Java中队列的使用 三、队列的模拟实现 四、力扣刷题演练 4.1 设计循环队列 4.2 用栈实现队列 4.3 最小栈 总结 前言 今天我…

日撸 Java 三百行day36

文章目录 day36 领接表1. 领接表知识点2.结合上图去抽象一个邻接表结点的对象3.广度优先遍历4.深度优先遍历 #说明 闵老师的文章链接&#xff1a; 日撸 Java 三百行&#xff08;总述&#xff09;_minfanphd的博客-CSDN博客 自己也把手敲的代码放在了github上维护&#xff1a;h…