JavaScript模块化开发

news/2024/4/24 12:23:52/文章来源:https://blog.csdn.net/weixin_56663198/article/details/130308016

目录:

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 = 18function 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 = 18export 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 = 18export 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.luyixian.cn/news_show_103069.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

R基础函数概览(一)

rep 函数形式&#xff1a;rep(x, time , length , each ,) 参数说明&#xff1a; x&#xff1a;代表的是你要进行复制的对象&#xff0c;可以是一个向量或者是一个因子。 times&#xff1a;代表的是复制的次数&#xff0c;只能为正数。负数以及NA值都会为错误值。复制是指的…

云原生(docker+k8s+阿里云)-Docker

Gitee-Kubernetes学习 kubectl备忘清单 k8s官方文档-task [云原生-kubectl命令详解] ingress详解 ingress官方文档 云原生-语雀-架构师第一课 从Docker到Kubernetes进阶-社区 云计算学习路线-阿里云大学 如上图&#xff0c;服务器有公网ip和私网ip&#xff0c;公网ip是外部访问…

Ubuntu20.04使用多卡训练HyperNetwork模型和LoRA模型全流程及疑难问题解决方案

目录 一. LoRA模型多卡训练1.1 安装xformer等库1.2 设置路径1.3 多卡训练 二. LoRA模型多卡训练疑难报错解决方案多卡训练报错 软硬件配置&#xff1a; CPU: AMD 5800 8core 16Thread GPU: NVIDIA RTX 3090 *1 NVIDIA TITAN RTX *1 OS: Ubuntu20.04 一. LoRA模型多卡训练 1.1 …

一篇终结synchronized

一&#xff1a;基本原理 Java对象在内存中由两部分组成 &#xff1a; 1 是成员变量 2 是对象头&#xff0c;以32位虚拟机介绍&#xff1a;此时对象头是64位&#xff0c;即8字节 其中32个字节代表 mark word 另外32个字节代表klass word分别是什么意思呢&#xff1f; 1 klass …

写题总结1

先把自己写完的总结一下&#xff1a; 题目一&#xff1a; 猫儿园的告示牌上贴着 ab 大小的矩形广告纸。猫猫对广告不感兴趣&#xff0c;她想知道能否用 cd 的矩形白纸完全覆盖这个广告。猫猫可以对白纸进行平移、旋转&#xff0c;但不能折叠或撕开等。如果可以完全覆盖输出 YE…

滴水逆向3期笔记与作业——01汇编

防止OneNote丢失。 海哥牛逼。 01汇编笔记 01进制进制定义10-2进制转换八进制 02数据宽度/逻辑运算数据宽度与存储逻辑运算计算机做加法的本质作业 03通用寄存器_内存读写通用寄存器表通用寄存器图内存读写计算机操作系统位数意义 04内存地址_堆栈寻址公式PUSH指令POP指令作业 …

【IAR工程】STM8S基于ST标准库读取DHT11数据

【IAR工程】STM8S基于ST标准库读取DHT11数据 ✨申明&#xff1a;本文章仅发表在CSDN网站&#xff0c;任何其他网站&#xff0c;未注明来源&#xff0c;见此内容均为盗链和爬取&#xff0c;请多多尊重和支持原创!&#x1f341;对于文中所提供的相关资源链接将作不定期更换。&…

4月有8本SCIE期刊被剔除(附MDPI/Frontiers/Hindawi最新在检期刊)

2023年4月SCI、SSCI期刊目录更新 2023年4月18日&#xff0c;科睿唯安更新了WOS期刊目录&#xff0c;继上次3月WOS期刊目录剔除50本SCIE&SSCI期刊之后&#xff0c;此次4月更新又有8本SCIE期刊发生变动&#xff0c;其中有4本期刊被踢出SCIE数据库&#xff0c;4本期刊更改了名…

流程图拖拽视觉编程--概述

一般的机器视觉平台采用纯代码的编程方式&#xff0c;如opencv、halcon&#xff0c;使用门槛高、难度大、定制性强、开发周期长&#xff0c;因此迫切需要一个低代码开发的视觉应用平台。AOI缺陷检测的对象往往缺陷种类多&#xff0c;将常用的图像处理算子封装成图形节点,如抓直…

Android 系统架构大图

android的系统架构和其操作系统一样&#xff0c;采用了分层的架构。从架构图看&#xff0c;android分为四个层&#xff0c;从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和Linux核心层。 1.应用程序 Android会同一系列核心应用程序包一起发布&#xff0c;该应用…

确定因果随机森林的树木数量 the number of trees

前言 推断因果性和分析异质性是统计学家在处理混杂任务中的圣杯。传统且主流的方法有:倾向性评分、分层分享、比例风险模型等。新的方法也有很多,代表就是:因果随机森林。这种算法,浅看难度一般,深入探索发现坑还是很多的。这篇博客不对算法做深入探讨,仅仅是我在阅读文…

Nautilus Chain :基于模块化架构的Layer3正在走向成熟

Nautilus Chain 是一个基于 Eclipse 和 Celestia 构建的模块化 Layer3 链。作为定位在 Layer0 的链基建概念&#xff0c;Eclipse 和 Celestia 为面向未来的区块链扩容技术提供了一套开发工具和基础框架。尽管这种前沿技术过去一直处于概念验证阶段&#xff0c;尚未推出适用于大…

Java并发(三)----创建线程的三种方式及查看进程线程

一、直接使用 Thread // 创建线程对象 Thread t new Thread() {public void run() {// 要执行的任务} }; // 启动线程 t.start(); 例如&#xff1a; // 构造方法的参数是给线程指定名字&#xff0c;推荐 Thread t1 new Thread("t1") {Override// run 方法内实现…

手把手教你PXE高效网络装机、Kickstart无人值守安装(详细版)

目录 一、部署PXE远程安装服务1.1PXE定义1.2PXE服务优点1.3搭建网络体系前提条件1.4 搭建PXE远程安装服务器 二. 实验2.1 服务器操作2.2 安装启动TFTP服务并修改TFTP服务的配置文件2.3 安装并启用DHCP服务2.4 准备linux内核&#xff0c;初始化镜像文件2.5 准备PXE引导程序2.6 安…

22、Tweak原理及部分逆向防护

一、Tweak原理 1.1 Tweak产物.dylib 执行make命令时,在 .theos的隐藏目录中,编译出obj/debug目录,包含 arm64、arm64e两种架构,同时生成readbadges.dylib动态库 在arm64、arm64e目录下,有各自架构的readbadges.dylib,而debug目录下的readbadges.dylib,是一个胖二进制文件 fi…

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

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

看完这篇文章你就彻底懂啦{保姆级讲解}-----(LeetCode刷题142环形链表II) 2023.4.24

目录 前言算法题&#xff08;LeetCode刷题142环形链表II&#xff09;—&#xff08;保姆级别讲解&#xff09;分析题目&#xff1a;算法思想环形链表II代码&#xff1a;补充 结束语 前言 本文章一部分内容参考于《代码随想录》----如有侵权请联系作者删除即可&#xff0c;撰写…

前端食堂技术周刊第 80 期:Vite 4.3、Node.js 20、TS 5.1 Beta、Windi CSS 即将落幕

美味值&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f; 口味&#xff1a;东坡肉 食堂技术周刊仓库地址&#xff1a;https://github.com/Geekhyt/weekly 本期摘要 Vite 4.3Node.js 20TypeScript 5.1 BetaWindi CSS 即将落幕Pretty TypeScri…

中医脉诊仪:结合传统与现代技术的诊断工具

一、引言 随着科技的不断发展&#xff0c;医学领域也取得了举世瞩目的进步。中医作为一种古老的医学体系&#xff0c;始终保持着其独特的魅力。脉诊作为中医诊断的重要方法之一&#xff0c;历经千年的发展和传承&#xff0c;如今在现代科技的助力下&#xff0c;诞生了中医脉诊…

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

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