前端Javascript模块化

2023-09-14 17:00:00

 🎬 岸边的风:个人主页

 🔥 个人专栏 :《 VUE 》 《 javaScript 》

⛺️ 生活的理想,就是为了理想的生活 !

在这里插入图片描述

目录

引言

前端模块化的发展历程

1.全局函数式编程

2.命名空间模式

3.CommonJS

require函数

module.exports

4.AMD(Asynchronous Module Definition)

5.UMD(Universal Module Definition)

6.ES6模块化

结论


 

引言

前端开发中,代码的组织和管理一直是开发者面临的一大挑战。随着Web应用日益复杂,对代码结构和组织的需求也更为明显。这种背景下,模块化编程应运而生,开发者们可以将复杂的代码拆分为可管理和可重用的模块。在本文中,我们将通过实际代码示例,来探索前端模块化的发展历程及各种模块化方案的实现原理。

前端模块化的发展历程

1.全局函数式编程

在早期的Web开发中,通常使用全局范围内声明函数和变量的方式来组织代码。例如:

var module1Data = 'module1 data';
function module1Func(){
    console.log(module1Data);
}

这种方式存在的问题主要有命名冲突、函数间依赖关系不明显、维护困难等。

2.命名空间模式

随着对代码组织方式的需求增加,开发者开始通过定义全局对象,将所有函数和变量封装在这个对象中,也就是命名空间模式。

var myApp = {
    module1Data: 'module1 data',
    module1Func: function(){
        console.log(this.module1Data);
    }
};

这种方式解决了全局命名冲突的问题,但是模块间的依赖关系依旧不明显,同时所有依赖都需要在命名空间对象中手动管理。

3.CommonJS

CommonJS模块规范是Node.js采用的规范,使用require函数加载模块,通过module.exports导出模块。

// a.js
module.exports = 'Hello world';

// b.js
var a = require('./a');
console.log(a); // 输出 'Hello world'

CommonJS使用同步加载方式,适用于服务器端,但由于网络请求的异步特性,不适合在浏览器环境使用。

require函数

require函数的主要任务是根据模块的文件路径读取模块文件,然后执行模块代码,最后返回模块的exports对象。

require函数的实现代码大致如下:

function require(modulePath){
    // 读取模块代码
    const code = fs.readFileSync(modulePath);
    
    // 包装模块代码
    const wrapper = Function('exports', 'require', 'module', '__filename', '__dirname', `${code}\n return module.exports;`);
    
    const exports = {};
    const module = { exports };
    
    // 执行模块代码
    wrapper(exports, require, module);
    
    // 返回模块的exports对象
    return module.exports;
}

其中,wrapper函数的参数exportsmodule就是模块的exportsmodule对象,这样我们就可以在模块中通过exportsmodule.exports来导出模块。

require函数在执行模块代码时,会先将模块代码包装到一个函数中,然后调用这个函数。这样做的好处是可以将模块代码隔离到一个函数作用域中,防止模块内的变量污染全局作用域。

module.exports

每个CommonJS模块都有一个module对象,这个对象有一个exports属性用于导出模块。当其他模块通过require函数加载这个模块时,就可以获取到module.exports对象。

module.exports的初始值是一个空对象{},我们可以添加属性到这个对象上,也可以直接将module.exports赋值为一个函数或其他类型的值。

例如,以下代码展示了如何使用module.exports导出一个函数:

// a.js
module.exports = function(){
    console.log('Hello world');
};

// b.js
const a = require('./a');
a(); // 输出 'Hello world'

以上就是CommonJS模块的实现原理。虽然CommonJS主要用于服务器端,但其模块化思想和实现方式对于前端模块化的发展有着深远影响。

4.AMD(Asynchronous Module Definition)

AMD规范是由RequireJS提出的,特点是异步加载模块,适合用在浏览器环境。

// AMD
define(['dependency'], function(){
    return 'module content';
});

AMD规范的语法较为复杂,但能在浏览器环境中异步加载模块。

5.UMD(Universal Module Definition)

UMD规范试图提供一种解决方案,让同一段代码在CommonJS和AMD环境中都能运行。

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
       

 define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node, CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // 浏览器全局变量
        root.returnExports = factory(root.jQuery);
    }
}(this, function ($) {
    // 模块代码
}));

UMD通过判断环境中是否存在defineexports对象,来判断是哪种模块环境,从而使用对应的模块化方案。

6.ES6模块化

ES6模块化是ECMAScript 6(ES2015)中新引入的模块系统,使用import关键字加载模块,通过export关键字导出模块。

// a.js
export const a = 'Hello world';

// b.js
import { a } from './a.js';
console.log(a); // 输出 'Hello world'

ES6模块化具有静态性,这种静态性质让依赖关系更加明显,有利于工具进行优化。此外,ES6模块是异步加载,也适合在浏览器环境中使用。

结论

模块化是前端开发中的一种重要的编程思想,它让代码组织更加清晰,便于维护和重用。经过多年的发展,前端模块化方案已经从简单的全局函数,发展到当前的ES6模块化。每一种模块化方案都有其适用场景,选择哪种方案主要取决于项目的需求。理解不同模块化方案的实现原理,可以帮助我们更好地使用和选择这些工具。

更多推荐

《动手学深度学习 Pytorch版》 7.1 深度卷积神经网络(LeNet)

7.1.1学习表征深度卷积神经网络的突破出现在2012年。突破可归因于以下两个关键因素:缺少的成分:数据数据集紧缺的情况在2010年前后兴起的大数据浪潮中得到改善。ImageNet挑战赛中,ImageNet数据集由斯坦福大学教授李飞飞小组的研究人员开发,利用谷歌图像搜索对分类图片进行预筛选,并利用亚马逊众包标注每张图片

QT基础教程(文本绘制)

文章目录前言一、普通文本绘制二、绘制旋转文本三、旋转文本升级总结前言本篇文章我们来讲解一下QT中使用QPainter来绘制文本的案例。一、普通文本绘制在Qt中,你可以使用QPainter类来绘制文本,包括普通文本、格式化文本和自定义文本效果。下面是使用QPainter绘制文本的基本方法和示例:1.绘制普通文本:使用QP

Shiro【核心功能、核心组件、项目搭建 、配置文件认证、数据库认证 】(一)-全面详解(学习总结---从入门到深化)

目录Shiro介绍_Shiro核心功能Shiro介绍_Shiro核心组件Shiro入门_项目搭建Shiro入门_配置文件认证Shiro入门_数据库认证Shiro认证_将Shiro对象交给容器管理Shiro介绍_Shiro简介Shiro是apache旗下的一个开源安全框架,它可以帮助我们完成身份认证,授权、加密、会话管理

解锁前端Vue3宝藏级资料 第五章 Vue 组件应用 5 (Vue 插件)

想了解Vue插件所以你看了官方文档却看不懂,或者你想知道Vue.use()方法和插件的关系。在本文档中,我们将参照文档讲解插件制作的基础知识,了解基础知识后,我们将制作与更实用的下拉菜单和脚本加载相关的插件。读完之后,您应该知道如何创建自己的插件以及如何添加插件。第一章Vue3项目创建1VueCLI创建vue项目第一章

Centos安装postgresql

一.执行安装命令与查看是否成功:1.yuminstall-ypostgresql-serverpostgresql-contrib2.安装后执行$psql--version或$psql-V可显示psql(PostgreSQL)9.2.243.另外,安装的同时还会创建postgres用户,Home为/var/lib/pg

构建无限画布,协作数字绘图 | 开源日报 0915

tldraw/tldrawStars:16.4kLicense:Apache-2.0tldraw是一个协作数字白板项目,可在tldraw.com上使用。它的编辑器、用户界面和其他底层库都是开源的,并且可以通过npm进行分发。您可以使用tldraw为产品创建一个即插即用的白板,或者将其作为构建自己无限画布应用程序的基础。

小程序开发一个多少钱啊

在今天的数字化时代,小程序已经成为一种非常流行的应用程序形式。由于它们的便捷性、易用性和多功能性,小程序吸引了越来越多的用户和企业。但是,很多人在考虑开发一个小程序时,都会遇到同一个问题:开发一个小程序需要多少钱?小程序的开发费用因人而异,取决于多种因素。下面,我们将为您详细列出影响小程序开发费用的主要因素。1、功能需

Bean的生命周期

SpringBean的生命周期是从Bean实例化之后,即通过反射创建出对象之后,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为SpringBean的生命周期。小枫叶一,实例化1.1Bean工厂后处理器–BeanFactoryPostProcessorBeanFactoryPostProcessor是一个

怎样判断一个数是否为偶数

要求代码行数尽可能少;packagemainimport("fmt""strconv")funcmain(){fmt.Printf("传入的值是否为奇数:%t\n",Judge_is_even(7))}funcJudge_is_even(numint)bool{//fmt.Println(num%2)rs,_:=str

modbus的协议

在介绍Modbus协议之前,我们要先了解下RS485协议,因为Modbus协议是在RS485这个硬件层协议上搭建的软件层协议。RS485特性半双工。用缆线两端的电压差值来表示传递信号。RS485的特点包括1.S485的电气特性:逻辑“1”以两线间的电压差为+(2~6)V表示;逻辑“0”以两线间的电压差为-(2~6)V表

ChatGPT Prompting开发实战(八)

一.什么是归纳总结式的prompt开发有时候需要对一段文本进行归纳总结,那么可以采取以下的方案:-按照给定单词、句子或者字符的数量限制来让模型裁剪文本,使内容更精炼-基于聚焦的主题进行总结-只根据需求抽取相关的文本信息,不需要整段文本内容除了上面列出的几种方式之外,还可能有额外的一些需求,譬如给出多段文本,要求模型同时

热文推荐