当前位置: 首页 > news >正文

JavaScript基础知识总结(六)模块化规范

模块化

什么是模块化

模块化是一种程序设计方案,指将程序拆分为多个功能单一,相对独立的模块。模块各司其职,互相协作。提升代码的可维护性与可读性。

**模块化主要解决的问题:**1.不同脚本之间可能会出现命名冲突,全局变量污染。2.依赖管理混乱,必须手动维护不同第三方依赖库的顺序。3.复用性很差,同一个函数可能需要在不同项目中重复定义。

**核心思想:**高内聚,低耦合。模块内部功能紧密相关,模块之间尽量减少依赖。

问题:在没有模块化的时候,解决问题的方法是什么?

在没有模块化标准时,开发者常使用 IIFE 实现作用域隔离(也就是立即调用函数)

(function() {var myModule = {greet: function() {console.log('Hello, world!');}};window.myModule = myModule; // 暴露接口
})();

缺点很明显,模块间的依赖不明确,缺乏导入导出机制,不适合用于大型项目

下面将按照不同模块化规范出现时间依次讲解。

CJS规范

CommonJS 这种模块化规范是专门为服务器端设计的模块化规范(Node.js)。是出现时间最早的模块化规范。

注意这个规范只适用于服务端与webpack等打包工具,不适用于浏览器。

核心变量:

CJS中有三个核心变量:exportsmodule.exports,require

模块化的核心就是导入和导出,三个变量里面module.exportsexports负责模块导出,require负责模块导入

基本使用
使用module.exports导出

在文件util.js中使用规范规则导出,module.exports导出需要导出的是一个对象,对象是包含的导出的内筒

// util.js
const info = {name: 'alex'
}module.exports = info

main.js文件中接收

// main.js
const moduleInfo = require('./util.js')

此时: util.js中的infomodule.exports的内存地址 与 main.js中的moduleInfo的内存是一样的 所以三者都指向的同一个内存地址上的同一个内容

使用exports导出

此时的exports本质上就是一个导出对象,这个对象可以挂载我们需要导出的属性

// foo.js
exports.foo = 'foo'
// index.js
const fooModule = require('./foo')console.log(fooModule.foo) // foo

本质上也是使用的是同一地址上的引用.

exports与module.exports的本质

通过上面两个导出的示例,我们可以总结一下这两个导出在引擎上有什么却别

module.exports = {}exports = module.exports

所以 使用 exports.xx = 'xxx' 其实就是往 module.exports = {} 这个对象中添加属

我们可以深究一下,exports本质就是一个引用类型的对象,module.exports本质与exports是同一个引用 只不过后者可以直接暴露属性,但是前者不能直接暴露属性

那么为什么有了 module.exports 后还需要一个 exports 呢?其实根据 CommonJS 的规范来说是要通过 exports 来导出的,但是由于 Node 本身实现是通过 module.exports 来实现的,所以在 Node 开发中经常会使用 module.exports 反而不经常使用 exports

require函数的查找模式

require(X):

  • X是Node提供的核心模块:‘http’,'path’模块等,那么require就会直接返回这个模块
  • X是./ ../ /开头的
    • 有后缀名如(.js等)
      • 按照后缀名格式查找
    • 没有后缀名
      • 先查找文件本身
      • 查找X.js
      • 查找X.json
      • 查找X.node
  • X 不是路径也不是核心模块(说明X可能是第三方库如"axios等等")
    • 会根据’module.path’一级一级去查找第三方库中node_moodules是否有X
  • 没有找到抛出异常not found
模块的加载过程

结论一:模块在被第一次引入时,模块中的 js 代码会被执行一次

// foo.js
console.log('foo module execute')
// main.js
require('./foo')  // 会运行一遍 foo 模块中的代码

结论二:模块在被多次加载后,代码也会只运行一次:

  • 这是因为每个模块对象有一个 loaded 属性
  • 加载了 loaded 就变为 true 了
require('./foo')  // 也只会运行一次 foo 模块
require('./foo')
require('./foo')
CJS规范的缺点:

CommonJS 模块的加载是同步的:

  • 同步意味着需要等模块中加载完毕后,后面的逻辑才会执行
  • 这个在服务器不会有什么问题,因为服务器加载的是本地 JS 文件,速度会很快

那么如果将 CommonJS 规范用于客户端(浏览器)呢?

  • 浏览器加载 js 文件需要先从服务端下载下来,之后再加载运行
  • 那么采用同步就意味着后续的 js 代码都无法正常运行,即使是一些简单的 DOM 操作

所以如果面向的是客户端,我们将不再采用 CommonJS 规范,在早期浏览器中如果使用模块化开发,通常会采用 AMD 和 CMD 规范。

  • 但是由于目前 ES 已经支持模块化 ESM(ES Module),另一方面借助于 webpack 等打包工具也可以将 CommonJS 和 ESM 模块的转换
  • 所以 AMD 和 CMD 用的已经非常少了,下面我们就简单的了解一下

AMD规范

AMD规范是主要用于浏览器的一种模块化规范,AMD是Asynchronous Module Definition(异步模块定义)的缩写

顾名思义,AMD规范是采用异步加载的模块化规范,AMD规范已经很少被使用了,实现AMD规范的库主要有require.jscurl.js

requires的使用

使用requires需要在入口文件加载前引用cdn

<script src='./lib/require.js' data-main="./index.js"></script>

导出模块

// /src/foo.js// 在 define 中写逻辑
define(function () {const name = 'foo'const age = 18function sum(num1, num2) {return num1 + num2}// 这里的 return 就导出了return {name,age,sum,}
})

引入模块

// /index.js// 先配置每个模块的路径
require.config({paths: {main: './src/main',foo: './src/foo',},
})// 这里再引入模块
require(['foo'], function (foo) {// 加载完成 foo 后触发回调 并传入加载的数据console.log(foo.name)console.log(foo.age)console.log(foo.sum(1, 2))
})

UMD规范

UMD 的全称是 Universal Module Definition,即 通用模块定义。它是一套 JavaScript 模块模式的组合,主要目的是让一个 JavaScript 模块能够在多种不同的环境中运行,尤其是同时支持:

  1. AMD - 异步模块定义,用于浏览器端,如 RequireJS。
  2. CommonJS - 用于服务器端,如 Node.js。
  3. 全局变量 - 作为浏览器中的全局变量使用,当没有模块加载器时。

简单来说,UMD 就是一种“通用”的 JavaScript 模块写法,它通过一系列条件判断,来检测当前代码运行在何种环境下,然后采用该环境对应的方式导出模块。

在 JavaScript 发展的早期,缺乏官方的模块标准。社区出现了多种模块化方案,但它们互不兼容。

  • 你写了一个库,如果只用 AMD 方式导出,那么在 Node.js 中就无法直接使用。
  • 如果只用 CommonJS 方式导出,在浏览器中没有模块加载器时也无法使用。

为了解决这个问题,开发者们创造了 UMD 模式。它让你的代码“自适应”环境,大大提高了库的通用性和可移植性。在 ES6 模块成为标准之前,UMD 是许多流行库(如 jQuery、React 等)的常见选择。

UMD 的本质是一个 立即执行函数表达式(IIFE),它接收一个工厂函数。在这个 IIFE 中,会进行一系列的条件判断,以决定如何导出模块。

这里就不介绍代码了

CMD规范

CMD是引用于浏览器的一种模块化规范(Common Module Definite 通用定义模块) 采用的是异步加载模块

使用的是SeaJS实现CMD规范

seajs的基本使用

在使用前需要引入seajs文件(或者使用CDN远程引入)

<script src="./lib/sea.js"></script>

导出模块

// /src/foo.jsdefine(function (require, exports, module) {const name = 'foo'const age = 18function sum(num1, num2) {return num1 + num2}// 可以通过 exports.name = name// 和 module.exports 两种module.exports = {name,age,sum,}
})

导入模块

// /index.js// define 函数接收一个回调函数,参数 require、exports、module
define(function (require, exports, module) {// 通过 require 导入模块const foo = require('./src/foo.js')console.log(foo)
})

ES6规范

ES Module 规范是 ES 提出的,所以是官方的模块化规范

ESM 和 CommonJS 的模块化有一些不同:

  • ESM 使用了 import (导入)和 export(导出)
  • ESM 采用编译期的静态分析,并且也加入了动态引用的方式
  • 采用 ESM 将自动采用严格模式 use strict

如果在 html 中引入 ESM 模块,需要这样:加上 type="module"

<script src="./index.js" type="module"></script>
导入导出的基本使用

导出

// 01.1xxxxlet title = "hello";
let url='www.baidu.com';
function say(){console.log("hello");
}
export{title,say}

导入

// 01.2xxxx
import{title,say}from './01.1模块的基本使用.js'
console.log(title);//很神奇吧
say()
//利用导出和导入 我们只需要暴露我们需要的功能就可以了
//如果在浏览器中使用 要给script加上type="module"
模块的具名导入和导出

具名导出

// ./05.2 xxxxx
export let site='www.baidu.com';//具名导出
export function add(a,b){return a+b;
}//必须要有名字 不然会报错

具名导入

// ./05.1xxxxxx
import {site} from "./05.2.js"
console.log(site);
import { add }  from "./05.2.js";
console.log(add(1, 2));
模块批量导入和导出

导出

// 06.2
export let site='www.baidu.com';//具名导出
export function add(a,b){return a+b;
}//必须要有名字 不然会报错

导入

/* 使用 * as 别名可以批量导入,但是打包时会认为我们要用到这个模块里面的所有内容,
导致打包文件的体积过大,建议使用具名导入,打包是只会打包我们用到的一些文件 */
// 批量导入
import * as api from "./06.2.js"
console.log(api);
console.log(api.site);
起别名

导出起别名

let site='houdunren.com'
export{site}
let sites=['www.baidu.com','www.taobao.com','www.jd.com']
export{sites as web};//导出起别名

导入起别名

import {site as site1, web} from './07.2.js';
console.log(site1);//site1是site的别名
console.log(web);//web是sites的别名
默认导出

导出时使用default关键字,一个文件中只能默认导出一次

class User{static render(){return 'user static render'}
}
export default User;

导入

import Use from "./08.2.js"console.log(Use.render())
混合导入与导出

默认导出和正常导出一起混合使用

混合导出

export default class User{static render(){return 'user static render'}
}
let site='URL_ADDRESS.baidu.com'export {site}

混合导入

import hd,{ site } from "./09.2.js"
console.log(hd.render());
console.log(site);
//如果是批量导入 就使用api.default
多个模块合并导出

导出文件1

export let site='www.baidu.com';//具名导出
export function add(a,b){return a+b;
}//必须要有名字 不然会报错

导出文件2

export default class User{static render(){return 'user static render'}
}
let site='URL_ADDRESS.baidu.com'export {site}

合并导出文件

import *as t3 from './10.3.js'
import *as t4 from './10.4.js'
export {t3,t4}

导入文件

import *as api from './10.2.js'
console.log(api);
console.log(api.t3.default.render());
http://www.dtcms.com/a/608186.html

相关文章:

  • 石台做网站首页页面设计模板
  • 江阴做网站的地方港口建设征收 申报网站
  • 网站服务器拒绝连接天津网站建设基本流程
  • php网站后台网站建设方案报价费用明细价格
  • 电商平台网站建设多少钱铁岭 建筑公司网站 中企动力建设
  • 网站的积分系统怎么做宜春建设局官方网站
  • 北京网站开发制作公司有那个网站做外贸
  • 想做个网站都需要什么南昌网站建设模板服务商
  • 网站seo源码网站开发 附加协议
  • 搭建自己的博客网站ps制作网站模板
  • 在哪里找做网站的客户东营市建设项目工伤保险是哪个网站
  • 软件开发网站建设建设网站广告语
  • 推荐扬中网站建设首页界面设计
  • 如何让自己做的网站在google搜索引擎上搜到衡水做外贸网站建设
  • 用dw如何做网站首页户外用品网站建设项目背景
  • 阿里巴巴个人网站怎么做京东的网络营销方式
  • 丁香人才网官方网站企业网站开发创意
  • 网站模板怎么样网站上传空间下一步
  • 长春seo网站排名优化wordpress地图插件
  • 商城类的网站怎么做优化大连网站排名优
  • 聂教练做0网站商城建设网站的原因
  • 淄博免费建站博客网站主页代码html
  • 为什么网站需要维护潍坊网站制作公司
  • 福清市建设局官方网站可以做女的游戏视频网站
  • 开网站的是啥公司怎样做投资理财网站
  • 做的比较好的网站有哪些网站建设运营预算
  • RV1126 NO.49:Rockx-SDK的简介
  • 南宁网站建设liluokj誉重网站建设案例
  • 快速网站优化服务论坛网站开发框架angular
  • 网站模板在线演示怎么做网站地图写法