javascript的模块化

news2024/9/20 0:44:45

1. 无模块化

script标签引入js文件,相互罗列,但是被依赖的放在前面,否则使用就会报错。如下:

  <script src="jquery.js"></script>
  <script src="jquery_scroller.js"></script>
  <script src="main.js"></script>
  <script src="other1.js"></script>
  <script src="other2.js"></script>
  <script src="other3.js"></script>

 即简单的将所有的js文件统统放在一起。但是这些文件的顺序还不能出错,比如jquery需要先引入,才能引入jquery插件,才能在其他的文件中使用jquery。缺点很明显:

  • 污染全局作用域
  • 维护成本高
  • 依赖关系不明显

2. CommonJS规范

在node中,默认支持的模块化规范叫做CommonJS,它使得 JavaScript 代码可以更好地组织、复用和维护。

关于模块:

  • 每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
  • 在模块中使用global定义全局变量,不需要导出,在别的文件中可以访问到。
  • 每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外接口。
  • 通过require加载模块,读取并执行一个js文件,然后返回该模块的exports对象。
  • 所有代码都运行在模块作用域,不会污染全局作用域。
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
  • 模块加载的顺序,按照其在代码中出现的顺序。

 一点说明:  

exports 是对 module.exports 的引用。比如我们可以认为在一个模块的顶部有这句代码: exports = module.exports所以,我们不能直接给exports赋值,比如number、function等。

var exports = module.exports
类似于
var obj1 = obj
这里exports只是module.exports的一个引用,所以这里直接给exports直接赋值,并不会影响module.exports,只是指向了新对象而已。
始终要记住:底层实现里最后返回的是module.exports对象

重新赋值,解除引用:

此外,这里要注意:一旦给exports重新赋值,便会失去和module.exports的关联,指向新对象,且后期无法使用。

一点优点:解决了依赖、全局变量污染的问题

一点缺点: CommonJS用同步的方式加载模块。在服务端,模块文件都存在本地磁盘,读取非常快,所以这样做不会有问题。但是在浏览器端,限于网络原因,CommonJS不适合浏览器端模块加载,更合理的方案是使用异步加载,比如AMD规范。

        

1.module对象

node内部提供一个Module构建函数。所有的模块其实都是Module的实例。

每个模块内部都有一个Module对象,代表当前模块。它有以下属性:

  • module.id,模块的识别符,通常是带有绝对路径的模块文件名;
  • module.filename,模块的文件名,带有绝对路径;
  • module.loaded,返回应boolean值,表示模块是否已经完成加载;
  • module.parent,返回一个对象,表示调用该模块的模块;
  • module.children,返回一个数组,表示该模块内用到的其他模块;
  • module.exports,表示模块对外输出的值。

2. CommonJS 模块的导出

// math.js
const sum = (a, b) => a + b;
const multiply = (a, b) => a * b;
module.exports = { sum, multiply };//暴露这两个函数


const a = 10
const b = 20
const obj = { name: "孙悟空" }

module.exports.a = a
module.exports.b = b
// const {a, b} = require("./m.js")



// math_functions.js
function add(a, b) {
  return a + b;
}
 
function subtract(a, b) {
  return a - b;
}
 
const PI = 3.14159;
 
module.exports = { add, subtract, PI };





const getName = () => {
  return 'Jim';
};

const getLocation = () => {
  return 'Munich';
};

const dateOfBirth = '12.01.1982';

exports.getName = getName;
exports.getLocation = getLocation;
exports.dob = dateOfBirth;








class User {
  constructor(name, age, email) {
    this.name = name;
    this.age = age;
    this.email = email;
  }

  getUserStats() {
    return `
      Name: ${this.name}
      Age: ${this.age}
      Email: ${this.email}
    `;
  }
}

module.exports = User;

3.其他module.exportsexports的常见问题

  • module.exportsexportsNode.js中有什么区别?

module.exports和exports都用于从模块中导出值。exports本质上是对module.exports的引用,所以您可以任选其一使用。然而,通常建议使用module.exports以避免潜在问题。

  • 我可以在同一个模块文件中同时使用module.exportsexports吗?

是的,您可以在同一个模块中同时使用两者。但在这样做时要小心,最好保持一致性,坚持使用一种惯例。
 

  • 在使用module.exportsexports时有哪些常见问题?

一个常见的是直接重新赋值exports,这可能导致意想不到的结果。最好使用module.exports以获得更好的一致性,并避免潜在的问题。

  • 我可以在浏览器中使用module.exportsexports吗,还是它们只适用于Node.js

module.exportsexports是特定于Node.js的,在浏览器的JavaScript中不可用。在浏览器中,通常使用其他机制,如ES6模块进行导出和导入。

4. CommonJS 模块的导入

2.1使用 require 函数导入文件模块(用户自定义)

  • 使用require(“模块的路径”)函数来引入模块
  • 模块名要以./ 或 …/开头
  • 扩展名可以省略(除了扩展名是.cjs)
  • 在 JavaScript 中,引入模块时可以省略文件扩展名。当引入的模块是 JavaScript 文件(.js)、JSON 文件(.json)和node(.node)时,可以不写扩展名,Node.js 会根据需要自动解析文件类型并加载对应的模块。
  • * 如果没有.js 后缀的同名文件它会寻找 .json后缀的。(如果两个后缀名都有,则优先导入后缀名为.js的)
  • .js > .json >.node

2.2使用 require 函数导入核心模块(Node.js 内置的模块)

  • 直接写核心模块的名字即可
  • 也可以在核心模块前添加 node:

// main.js
const math = require('./math.js');
console.log(math.sum(2, 3)); // 输出 5
console.log(math.multiply(2, 3)); // 输出 6
 

2.3文件夹作为模块


当我们使用一个文件夹作为模块时,文件夹中必须有一个模块作为主文件。如果文件夹中含有package.json文件且文件中设置了main属性,则main属性指定的文件会成为主文件,导入模块时就会导入该文件(主文件)。如果没有package.json,则node会按照index.js、index.node的顺序寻找主文件。

//01module.js
// reauire是用来加载模块的,它会把引进来的东西作为返回值返回
// const result = require('./外部')
const result = require('./文件')//它会执行引入模块内的代码但是它的返回值就是模块内导出(暴露/exports/module.exports)的东西,如果模块未导出(暴露)任何东西,那么它就是空
console.log(result)

被导入的文件夹

index.js


console.log('我是入口')
require('./a')
require('./b')
require('./c')
require('./d')
// console.log('ff')`

a.js

console.log('我是a')

b.js

console.log('我是b')

c.js

console.log('我是c')

d.js

console.log('我是d')

注意此时打印result内容为空,这是因为虽然引入了,但是被引入发的模块没有暴露东西(在模块内部任何变量或其他对象都是私有的,需要手动暴露)
用module.exports暴露后

//index.js
console.log('我是入口')
require('./a')
require('./b')
require('./c')
require('./d')
// console.log('ff')`
const a = 10
const b = 20
module.exports.a = a
module.exports.b = b

再次执行,result对象内为我们暴露的东西

2.4模块的原理

(function(exports, require,module,_filename,__dirname)
let a= 10
let b=20
});

用module.exports导出和用exports导出有什么异同?
答:他俩都是对象,但是exports是module.exports的引用,所以exports只能添加属性(exports直接赋值会改变exports的引用,而不会改变module.exports的引用,从而起不到导出的效果),不能直接赋值,而module.exports可以直接赋值。

3. AMD规范

AMD规范则是非同步加载模块允许指定回调函数,AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。

AMD标准中,定义了下面三个API:

  1. require([module], callback)
  2. define(id, [depends], callback)
  3. require.config()

即通过define来定义一个模块,然后使用require来加载一个模块, 使用require.config()指定引用路径。

先到require.js官网下载最新版本,然后引入到页面,如下:

<script data-main="./alert" src="./require.js"></script>

data-main属性不能省略。

 

以上分别是定义模块,引用模块,运行在浏览器弹出提示信息。

      引用模块的时候,我们将模块名放在[]中作为reqiure()的第一参数;如果我们定义的模块本身也依赖其他模块,那就需要将它们放在[]中作为define()的第一参数。

     在使用require.js的时候,我们必须要提前加载所有的依赖,然后才可以使用,而不是需要使用时再加载。

一点优点:适合在浏览器环境中异步加载模块、并行加载多个模块

一点缺点:不能按需加载、开发成本大

4. CMD

AMD 推崇依赖前置、提前执行CMD推崇依赖就近、延迟执行。CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。

很明显,CMD是按需加载,就近原则。

5. ES6模块化

在ES6中,我们可以使用 import 关键字引入模块,通过 exprot 关键字导出模块,功能较之于前几个方案更为强大,也是我们所推崇的,但是由于ES6目前无法在浏览器中执行,所以,我们只能通过babel将不被支持的import编译为当前受到广泛支持的 require。 

 

es6在导出的时候有一个默认导出,export default,使用它导出后,在import的时候,不需要加上{},模块名字可以随意起。该名字实际上就是个对象,包含导出模块里面的函数或者变量。

但是一个模块只能有一个export default

6. CommonJs和ES6区别

(1) CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。

  • CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
  • S6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

    (2) CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。

  • 运行时加载: CommonJS 模块就是对象;即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。

  • 编译时加载: ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,import时采用静态命令的形式。即在import时可以指定加载某个输出值,而不是加载整个模块,这种加载称为“编译时加载”。

CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

 

(3)

  • exports只能使用语法来向外暴露内部变量:如exportts.xxx =xxx;
  • module.exports既可以通过语法,也可以直接赋值一个对象

小节:

1、exports为modules.exports的一个引用
2、最后node底层模块导出的是module.exports
3、底层代码
    var module = {
        exports:{...}
    } 
4、exports.name等价于module.exports.name,但node为了方便书写,使用module.exports导出单个成员,本质为将该子对象重新赋值  
5、所以只要给exports赋值,便丢失了module.exports的引用关系,后期便不可用   

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

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

相关文章

Linux block_device gendisk和hd_struct到底是个啥关系

本文的源码版本是Linux 5.15版本&#xff0c;有图有真相&#xff1a; 1.先从块设备驱动说起 安卓平台有一个非常典型和重要的块设备驱动&#xff1a;zram&#xff0c;我们来看一下zram这个块设备驱动加载初始化和swapon的逻辑&#xff0c;完整梳理完这个逻辑将对Linux块设备驱…

.NET 一款用于解密web.config配置的工具

01阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&#xf…

位运算:带带孩子吧,孩子很强的!

快速进制 在聊到位运算之前&#xff0c;不妨先简单过一遍二进制的东西。熟悉二进制和十进制的快速转换确实是掌握位运算的基础&#xff0c;因为位运算直接在二进制位上进行操作。如果不熟悉二进制表示&#xff0c;很难直观理解位运算的效果。 这里主要涉及二进制和十进制之间…

蓝桥杯嵌入式国三备赛经验分享

1 学习STM32入门视频 向大家推荐一套宝藏级别的视频&#xff1a;【STM32入门教程-2023版 细致讲解 中文字幕】 如果已经比过蓝桥杯单片机或学习过单片机相关课程的同学&#xff0c;你们可以尝试不需要STM32套件进行学习。如果没有学过单片机相关课程的同学&#xff0c;可以买…

直击智博会,supOS加快发展新质生产力,赋能全球工厂数字化转型

9月6日&#xff0c;第十四届智慧城市与智能经济博览会&#xff08;以下简称智博会&#xff09;开幕主题活动在宁波举办。本届智博会着重围绕“数字赋能新型工业化”主题&#xff0c;设置开幕活动、展览展示和前瞻研讨、产数合作、赛事赋能、开放活动等4大板块活动&#xff0c;旨…

全球AI产品Top100排行榜

Web Top50的榜单里&#xff0c;AIGC类型的应用占比52%&#xff0c;遥遥领先。AIGC类型包括图像、视频、音乐、语音等的内容生成和编辑。音乐生成应用Suno在过去六个月中的排名跃升最为显著&#xff0c;从第36位上升至第5位。排名第二大类是通用对话/AI聊天/角色扮演类型的应用&…

银河麒麟系统开机自动进入指定账户(如:root)桌面

目录 1. 需求的提出 2. 机器环境说明 3. 解决方法 4. 附加说明 1. 需求的提出 编写好的软件在客户的装有银河麒麟操作系统的机器上运行&#xff0c;但有些操作必须用root权限才能操作&#xff0c;如&#xff1a;打开串口。Linux下的普通账户打开串口时提示权限不足。在普通…

【HarmonyOS NEXT】实现截图功能

【HarmonyOS NEXT】实现截图功能 【需求】 实现&#xff1a;实现点击截图按钮&#xff0c;实现对页面/组件的截图 【步骤】 编写页面UI Entry Component struct Screenshot {BuildergetSnapContent() {Column() {Image().width(100%).objectFit(ImageFit.Auto).borderRadi…

C++入门(06)安装QT并快速测试体验一个简单的C++GUI项目

文章目录 1. 清华镜像源下载2. 安装3. 开始菜单上的 QT 工具4. 打开 Qt Creator5. 简单的 GUI C 项目5.1 打开 Qt Creator 并创建新项目5.2 设计界面5.3 添加按钮的点击事件5.4 编译并运行项目 6. 信号和槽&#xff08;Signals and Slots&#xff09; 这里用到了C类与对象的很多…

网络协议详解

目录 1.认识网络协议 2网络协议的设计 2.1网络通信的问题 2.2网络协议的分层设计 软件分层与网络分层 3.OSI七层网络模型 各层次的介绍如下 4.TCP/IP 五层协议 各层次说明 各层次所解决的问题 5.网络和操作系统之间的关系 单主机下 多主机下 6.重新理解网络协议 …

【鸿蒙HarmonyOS NEXT】页面之间相互传递参数

【鸿蒙HarmonyOS NEXT】页面之间相互传递参数 一、环境说明二、页面之间相互传参 一、环境说明 DevEco Studio 版本&#xff1a; API版本&#xff1a;以12为主 二、页面之间相互传参 说明&#xff1a; 页面间的导航可以通过页面路由router模块来实现。页面路由模块根据页…

kubernetes微服务基础及类型

目录 1 什么是微服务 2 微服务的类型 3 ipvs模式 ipvs模式配置方式 4 微服务类型详解 4.1 ClusterIP 4.2 ClusterIP中的特殊模式headless 4.3 nodeport 4.4 metalLB配合loadbalance实现发布IP 1 什么是微服务 用控制器来完成集群的工作负载&#xff0c;那么应用如何暴漏出去&…

JavaWeb——JavaScript(3/4)-JS对象:BOM、DOM(Window、Location,概念、标准模型、获取元素对象)

目录 BOM 介绍 Window 案例(1) Location DOM 概念 标准模型 获取元素对象 案例(2) 原始代码 完整代码 JS对象 BOM 介绍 概念&#xff1a;Browser Object Model 浏览器对象模型&#xff0c;允许JavaScript与浏览器对话&#xff0c;JavaScript 将浏览器的各个组成部…

git 提交自动带上storyid

公司里的运维团队的产品经理&#xff0c;那老六提出说要在每个提交带上的jira storyid或者bugid&#xff0c;不用他自己弄不顾他人麻烦&#xff0c;真想问候他的xx。不过既然已经成为定局&#xff0c;还是想想有没有其他办法。经一番调研&#xff0c;网上有比较零碎的信息&…

攻防世界--->地穴

前言&#xff1a;学习笔记。 下载 解压 查壳。 64位ida打开。 进入主函数。 很容易得知&#xff0c;这是一个RC4加密。 【 &#xff08;题外话&#xff09; 在reverse中&#xff0c;RC4考点&#xff0c;不会很难。 reverse中RC4关键点就是&#xff0c;抓住异或。 一般解这种…

Open a folder or workspace... (File -> Open Folder)

问题&#xff1a;vscode Open with Live Server 时 显示Open a folder or workspace... (File -> Open Folder)报错 解决&#xff1a;不可以单独打开文件1.html ; 需要在文件夹里打开 像这样

【哈希表】深入理解哈希表

目录 1、哈希表简介2、哈希函数2.1、概念2.2、常用的哈希函数2.2.1、直接定址法2.2.2、除留余数法2.2.3、平方取中法2.2.4、基数转换法 3、哈希冲突3.1、概念3.2、开放地址法【闭散列&#xff1a;key存放到冲突位置的“下一个”空位置】3.3、链地址法【开散列&#xff1a;冲突位…

SAM 2:分割图像和视频中的任何内容

文章目录 摘要1 引言2 相关工作3 任务&#xff1a;可提示视觉分割4 模型5 数据5.1 数据引擎5.2 SA-V数据集 6 零样本实验6.1 视频任务6.1.1 提示视频分割6.1.2 半监督视频对象分割6.1.3 公平性评估 6.2 图像任务 7 与半监督VOS的最新技术的比较8 数据和模型消融8.1 数据消融8.2…

dr 航迹推算 知识介绍

DR&#xff08;Dead Reckoning&#xff09;航迹推算是一种在航海、航空、车辆导航等领域中广泛使用的技术&#xff0c;用于估算物体的位置。DR航迹推算主要通过已知的初始位置和运动参数&#xff08;如速度、方向&#xff09;来预测物体的当前位置。以下是 DR 航迹推算的详细知…

跨平台电商数据整合:item_get API在电商大数据平台中的角色

在电商行业蓬勃发展的今天&#xff0c;跨平台运营已成为众多商家的必然选择。然而&#xff0c;随之而来的数据孤岛问题却成为了制约电商企业进一步发展的瓶颈。为了解决这一问题&#xff0c;电商大数据平台应运而生&#xff0c;而item_get API作为获取商品详情的关键接口&#…