JS模块化

2023-09-22 00:50:41

JS模块化

什么是模块化?

将一个复杂的程序依据一定的规则(规范)封装成几个块(文件),并进行组合在一起。

块的内部数据/实现是私有的,只是向外部暴露一些接口(方法)与外部其它模板通信。

把所有的js代码写在一起,功能点不明确,耦合度不够,很难维护。

模块化的优点
  1. 避免命名冲突,减少命名空间污染
  2. 更好的分离,按需加载
  3. 更高复用性
  4. 高可维护性
页面引入加载script

引入的过多,发的请求就会过多 依赖模糊 并且要注意引用的顺序 难以维护

常见的模块化规范和工具

CommonJS(通用模块化规范)
规范
说明
  • 每个文件都可以当作一个模块
  • 在服务器端:模块的加载时运行时同步加载的-->会发生阻塞
  • 在浏览器端:模块需要提前编译打包处理 
实现
服务器端实现

基本语法

暴露模块

//value可以是任意的数据类型
1.module.exports = value
2.exports.xxx = value 
//暴露的模块到底是什么? 暴露的本质都是exports这个对象
//原本exports就是空的对象

引入模块

require(xxx)
第三方模块 :xxx为模块名
自定义模块:xxx为模块文件路径

下载第三方模块 npm install xx

模块化编码 

##app.js
//引入第三方库时要放到自定义库的上面
let uniq = require('uniq')
//将其他模块汇聚到主模块
let module1 =require('./modules/module1')
let module2 =require('./modules/module2')
let module3 =require('./modules/module3')

//如何使用
module1.foo()
module2()
module3.bar()
module3.foo()
let result = uniq(module3.arr)
console.log(result)

##module1.js
//module.exports = value
module.exports ={
    msg:'module1',
    foo(){
        console.log(this.msg);
    }
}

##module2.js
//暴露一个函数  module.exports =function(){}
module.exports=function(){
    console.log('module2');
}
//再写一个的话 module1.exports对象会被覆盖


##module3.js
//exports.xxx = value
//用这种方式暴露就是无限的给对象添加属性
exports.foo=function (){
    console.log('foo()module3');
}
exports.bar=function (){
    console.log('bar()module3');
}
exports.arr=[1,1,2,3,4,5,1]

 

浏览器端实现
 |-js
    |-dist //打包生成文件的目录
    |-src //源码所在的目录
      |-module1.js
      |-module2.js
      |-module3.js
      |-app.js //应用主源文件
  |-index.html
  |-package.json
    {
      "name": "browserify-test",
      "version": "1.0.0"
    }
## module1.js
module.exports = {
    foo() {
      console.log('moudle1 foo()')
    }
  }

## module2.js
module.exports = function () {
      console.log('module2()')
    }

## module3.js
 exports.foo = function () {
      console.log('module3 foo()')
    }
    
 exports.bar = function () {
      console.log('module3 bar()')
    }


## app.js
//引用模块
    let module1 = require('./module1')
    let module2 = require('./module2')
    let module3 = require('./module3')
    
    let uniq = require('uniq')
    
    //使用模块
    module1.foo()
    module2()
    module3.foo()
    module3.bar()
    
    console.log(uniq([1, 3, 1, 4, 3]))

 

AMD(异步模块定义)
规范
说明

专门用于浏览器端,模块的加载是异步的。

基本语法

定义暴露模块

//定义没有依赖的模块
define(function(){
    return 模块
})

//定义有依赖的模块
//第一个参数必须是一个数组,数组里面放置的是依赖的模块 第二个参数是函数 函数要有形参
define(['module1','module2'],function(m1,m2){
    return 模块
})

引入使用模块

require(['module1','module2'],function(m1,m2){
    使用m1/m2
})
实现
非AMD实现

## dataService.js
// 定义一个没有依赖的模块
(function(window){
    let name='dataService.js';
    function getName(){
        return name
    }
    window.dataService={getName};
})(window)

## alerter.js
// 定义一个有依赖的模块
(function(window,dataService){
    let msg='alerter.js'
    function showMsg(){
        console.log(msg,dataService.getName());
    }
    window.alerter={showMsg};
})(window,dataService)

## app.js
(function (alerter) {
    alerter.showMsg();
})(alerter)

## test.html
<script src="./js/dataService.js"></script>  //由于alerter.js依赖于dataService,所以也要在引入alerter之前引入dataService.js文件
<script src="./js/alerter.js"></script>  //引入alerter.js文件
<script src="./app.js"></script>  //单独引入app.js找不到alerter文件
AMD实现

##dataService.js
// 定义没有依赖的模块
define(function () {
    let msg = 'atguigu.com'
    function getMsg() {
        return msg
    }
    // 暴露模块
    return { getMsg }
})

##alerter.js
// 定义有依赖模块
define(['dataService'], function (dataService) {
    let name = 'Tom2'
    function showMsg() {
        console.log(name, dataService.getMsg());
    }
    // 暴露模块
    return { showMsg }
})

##main.js
// 引入模块
(function () {
    // 配置
    require.config({
        //映射: 模块标识名: 路径
        paths: {
            //自定义模块
            alerter: './modules/alerter',
            dataService: './modules/dataService',

        },
    })
    // 引入模块使用
    requirejs(['alerter'], function (alerter) {
        alerter.showMsg();
    })
})()

##index.html
<script data-main="js/main.js" src="js/libs/require.js"></script>
##先加载require.js文件,然后加载main.js

CMD (简单了解即可)
ES6(目前应用最广泛)

ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性

  • 依赖模块需要编译打包处理;
  • 导出模块: export;
  • 引入模块: import;
  • 使用Babel将ES6编译为ES5代码;(有的浏览器不支持)
  • 使用Browserify编译打包js;(require语法)

1.定义package.json文件

 {
   "name" : "es6-babel-browserify",
   "version" : "1.0.0"
 }

2.安装 

npm install babel-cli browserify -g	
npm install babel-preset-es2015 --save-dev 

 3。定义.babelrc文件

	{
    "presets": ["es2015"]
  }

 4.编码

##js/src/module1.js
// 暴露模块  分别暴露
export function foo(){
    console.log('foo() module1');
}
export function bar(){
    console.log('bar() module1');
}
export let arr=[1,2,3,4,5]


## js/src/module2.js
// 统一暴露
function fun() {
    console.log('fun() module2');
}
function fun2() {
    console.log('fun2() module2');
}
export { fun, fun2 };

## js/src/module3.js
//默认暴露  可以暴露任意数据类型,暴露什么数据类型,暴露什么数据接收到的就是什么数据
// export default value

// 方式一:
/* export default ()=>{
    console.log('我是默认暴露的箭头函数');
} */

// 方式二:
export default {
    msg: '默认暴露',
    foo() {
        console.log(this.msg);
    }
}

 ## js/src/app.js
//引入其他的模块  
//语法:import xxx from '路径'

import module1 from './module1'
import module2 from './module2'
console.log(module1,module2);  //undefined  undefined 

译并在index.html中引入
使用Babel将ES6编译为ES5代码(但包含CommonJS语法) :

babel js/src -d js/lib


使用Browserify编译js :

browserify js/lib/app.js -o js/lib/bundle.js


然后在index.html文件中引入

 <script type="text/javascript" src="js/lib/bundle.js"></script>

参考:

视频-尚硅谷

博客

最全面、最详细的“前端模块化”总结_编程三昧的博客-CSDN博客

前端模块化详解(完整版)_浪里行舟的博客-CSDN博客

前端模块化详解_最美的太阳-的博客-CSDN博客

更多推荐

Websocket集群解决方案以及实战(附图文源码)

最近在项目中在做一个消息推送的功能,比如客户下单之后通知给给对应的客户发送系统通知,这种消息推送需要使用到全双工的websocket推送消息。所谓的全双工表示客户端和服务端都能向对方发送消息。不使用同样是全双工的http是因为http只能由客户端主动发起请求,服务接收后返回消息。websocket建立起连接之后,客户端

WebMvcConfigurerAdapter、WebMvcConfigurer、WebMvcConfigurationSupport

WebMvcConfigurerAdapter、WebMvcConfigurer、WebMvcConfigurationSupport的关系?WebMvcConfigurerAdapter、WebMvcConfigurer和WebMvcConfigurationSupport是SpringMVC框架中用于配置Web应用

android系统目录结构

文章目录android系统目录结构问答偏好设置保存在哪里在应用设置中点击清除数据,清除的是什么在应用设置中点击清除缓存,清除的是什么参考android系统目录结构/-system(一般只有root权限才能访问)-data-app(存放应用程序的APK文件)-data(内部存储)-<安装的应用包名>-app_textur

lock和synchronized的区别

lock和synchronized都是在多线程环境下用于保护共享资源的机制,但它们有一些重要的区别:实现方式:synchronized是Java语言内置的关键字,可以用于方法或代码块级别的同步。Lock是一个接口,位于java.util.concurrent.locks包下,提供了更灵活的锁定机制。灵活性:Lock提供

SQL-4大板块(存储过程、函数、视图、触发器)

一、存储过程(做复杂运算)1.做复杂运算,是对变量做运算;2.可以对多个表进行update、insert、delete、select、query;3.可以在最终结果返回多个表,但是对对接环境有苛刻要求,比如:VB不支持接收返回多个表4.当一个查询语句无法实现,或者语句查询速度很慢时,想提高效率就会用到存储过程。先把需要

MongoDB——将时间戳转换为日期

在MongoDB中将时间戳转换为日期从timestamp转换为日期取决于我们保存时间戳的类型。它是对象、数字还是字符串类型?我们可以在mongoshell上使用以下命令检查字段的类型。在本教程中,我们将学习如何将时间戳转换为数字、字符串或对象类型的日期。检查字段类型://MongoDB5.0.8>typeofdb.co

滑动时间窗口的思想和实现,环形数组,golang

固定时间窗口在开发限流组件的时候,我们需要统计一个时间区间内的请求数,比如以分钟为单位。所谓固定时间窗口,就是根据时间函数得到当前请求落在哪个分钟之内,我们在统计的时候只关注当前分钟之内的数量,即[0s,60s],因为流量并不是均匀的,所以就会出现,在两个分钟之间超过阈值,1分50秒时来了150个请求,在2分10秒时来

图像语义分割概述

图像语义分割概述一、图像语义分割概念图像语义分割(ImageSemanticSegmentation)是一项计算机视觉任务,其目标是将输入的图像分割成多个区域,并为每个像素分配一个语义类别标签,以表示该像素属于图像中的哪个物体或区域。与其他图像分割任务不同,图像语义分割不仅关注于分割图像,还要理解图像中不同部分的语义含

【C++】面向对象编程示例 ( 案例需求 | Visual Studio 创建类 | 类的声明 | 类的实现 | 类的调用 )

文章目录一、案例需求二、VisualStudio创建类三、类的声明四、类的实现五、类的调用一、案例需求使用C++面向对象,抽象出一个立方体类;立方体有长/宽/高/面积/体积私有成员变量,以及访问这些成员变量的公共成员方法;还提供立方体的对比函数,对比2个立方体对象是否相等;二、VisualStudio创建类在Visua

【C++】类的声明 与 类的实现 分开 ① ( 类的声明 与 类的实现 常用用法 | Visual Studio 2019 中创建类的头文件和源文件 | 确保头文件包含一次 )

文章目录一、类的声明与类的实现分开1、类的声明与类的实现常用用法2、VisualStudio2019中创建类的头文件和源文件3、Student.h类头文件解析4、确保头文件包含一次一、类的声明与类的实现分开1、类的声明与类的实现常用用法在之前的博客中,定义的class类,定义类时同时也完成了实现;但是在C++语言实际开

“源启2.0”:从自上而下的解构,到自下而上的重构

从垂直打穿、到应用重构,中电金信赋能行业数字化转型之路既“向下走”、也“向上看”。“向上”先理解和吃透客户的企业战略,进而自上而下地将企业战略拆解为业务架构,“向下”再将业务架构拆解为应用架构和数据架构,并进一步对齐技术架构。而在此过程中,上至“应用重构”,下至“数字基础设施重构”就都已不是问题。这就是“源启2.0”的

热文推荐