首页 web前端 js教程 Js中的模块化是如何实现的

Js中的模块化是如何实现的

Jan 09, 2018 pm 05:01 PM
javascript 实现 模块化

由于 Js 起初定位的原因(刚开始没想到会应用在过于复杂的场景),所以它本身并没有提供模块系统,随着应用的复杂化,模块化成为了一个必须解决的问题。本着菲麦深入原理的原则,很有必要来揭开模块化的面纱,本文主要介绍了详解Js中的模块化是如何实现的,详细的介绍了模块化的运行,具有一定的参考价值,有兴趣的可以了解下,希望能帮助到大家。

一、模块化需要解决的问题

要对一个东西进行深入的剖析,有必要带着目的去看。模块化所要解决的问题可以用一句话概括

在没有全局污染的情况下,更好的组织项目代码

举一个简单的栗子,我们现在有如下的代码:

function doSomething () {
 const a = 10;
 const b = 11;
 const add = function (a + b) {
  return a + b
 }
 add (a + b)
}
登录后复制

在现实的应用场景中,doSomething 可能需要做很多很多的事情,add 函数可能也更为复杂,并且可以复用,那么我们希望可以将 add 函数独立到一个单独的文件中,于是:

// doSomething.js 文件
const add = require('add.js');
const a = 10;
const b = 11;
add(a+ b);
登录后复制
// add.js 文件
function add (a, b) {
 return a + b;
}
module.exports = add;
登录后复制

这样做的目的显而易见,更好的组织项目代码,注意到两个文件中的 require 和 module.exports,从现在的上帝视角来看,这出自 CommonJS 规范(后文会有一个章节来专门讲规范)中的关键字,分别代表导入和导出,抛开规范而言,这其实是我们模块化之路上需要解决的问题。另外,虽然 add 模块需要得到复用,但是我们并不希望在引入 add 的时候造成全局污染

二、引入的模块如何运行

在上述的例子中,我们已经将代码拆分到了两个模块文件当中,在不造成全局污染的情况下,如何实现 require,才能使得例子中的代码做到正常运行呢?

先不考虑模块文件代码的载入过程,假设 require 已经可以从模块文件中读取到代码字符串,那么 require 可以这样实现

function require (path) {
  // lode 方法读取 path 对应的文件模块的代码字符串
  // let code = load(path);
  // 不考虑 load 的过程,直接获得模块 add 代码字符串
  let code = 'function add(a, b) {return a+b}; module.exports = add';
  // 封装成闭包
  code = `(function(module) {$[code]})(context)`
  // 相当于 exports,用于导出对象
  let context = {};
  // 运行代码,使得结果影响到 context
  const run = new Function('context', code);
  run(context, code);
  //返回导出的结果
  return context.exports;
}
登录后复制

这有几个要点:

1) 为了不造成全局污染,需要将代码字符串封装成闭包的形式,并且导出关键字 module.exports ,module 是与外界联系的唯一载体,需要作为闭包匿名函数的入参,与引用方传入的上下文 context 进行关联

2) 使用 new Function 来执行代码字符串,估计大部分同学对 new Function 是不熟悉的,因为一般情况下定义一个函数无需如此,要知道,用 Function 类可以直接创建函数,语法如下:

var function_name = new function(arg1, arg2, ..., argN, function_body)
登录后复制

在上面的形式中,每个 arg 都是一个参数,最后一个参数是函数主体(要执行的代码)。这些参数必须是字符串。也就是说,可以使用它来执行字符串代码,类似于 eval,并且相比 eval, 还可以通过参数的形式传入字符串代码中的某些变量的值

3)如果曾经你有疑惑过为什么规范的导出关键字只有 exports 而我们实际使用过程中却要使用module.exports(写过 Node 代码的应该不会陌生),那在这段代码中就可以找到答案了,如果只用 exports 来接收 context,那么对 exports 的重新赋值对 context 不会有任何影响(参数的地址传递),不信将代码改成如下形式再跑一跑:

演示结果

三、代码载入方式

解决了代码的运行问题,还需要解决模块文件代码的载入问题,根据上述实例,我们的目标是将模块文件代码以字符串的形式载入

在 Node 容器,所有的模块文件都在本地,只需要从本地磁盘读取模块文件载入字符串代码,再走上述的流程就可以了。事实证明,Node 非内建、核心、c++ 模块的载入执行方式大体如此(虽然使用的不是 new Function,但也是一个类似的方法)

在 RN/Weex 容器,要载入一个远程 bundle.js,可以通过 Native 的能力请求一个远程的 js 文件,再读取成字符串代码载入即可(按照这个逻辑,Node 读取一个远程的 js 模块好像也无不可,虽然大多数情况下我们不需要这么做)

在浏览器环境,所有的 Js 模块都需要远程读取,尴尬的是,受限于浏览器提供的能力,并不能通过 ajax 以文件流的形式将远程的 js 文件直接读取为字符串代码。前提条件无法达成,上述运行策略便行不通,只能另辟蹊径

这就是为什么有了 CommonJs 规范了,为什么还会出现 AMD/CMD 规范的原因

那么浏览器上是怎么做的呢?在浏览器中通过 Js 控制动态的载入一个远程的 Js 模块文件,需要动态的插入一个

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

华为手机如何实现双微信登录? 华为手机如何实现双微信登录? Mar 24, 2024 am 11:27 AM

华为手机如何实现双微信登录?随着社交媒体的兴起,微信已经成为人们日常生活中不可或缺的沟通工具之一。然而,许多人可能会遇到一个问题:在同一部手机上同时登录多个微信账号。对于华为手机用户来说,实现双微信登录并不困难,本文将介绍华为手机如何实现双微信登录的方法。首先,华为手机自带的EMUI系统提供了一个很便利的功能——应用双开。通过应用双开功能,用户可以在手机上同

PHP编程指南:实现斐波那契数列的方法 PHP编程指南:实现斐波那契数列的方法 Mar 20, 2024 pm 04:54 PM

编程语言PHP是一种用于Web开发的强大工具,能够支持多种不同的编程逻辑和算法。其中,实现斐波那契数列是一个常见且经典的编程问题。在这篇文章中,将介绍如何使用PHP编程语言来实现斐波那契数列的方法,并附上具体的代码示例。斐波那契数列是一个数学上的序列,其定义如下:数列的第一个和第二个元素为1,从第三个元素开始,每个元素的值等于前两个元素的和。数列的前几个元

如何在华为手机上实现微信分身功能 如何在华为手机上实现微信分身功能 Mar 24, 2024 pm 06:03 PM

如何在华为手机上实现微信分身功能随着社交软件的普及和人们对隐私安全的日益重视,微信分身功能逐渐成为人们关注的焦点。微信分身功能可以帮助用户在同一台手机上同时登录多个微信账号,方便管理和使用。在华为手机上实现微信分身功能并不困难,只需要按照以下步骤操作即可。第一步:确保手机系统版本和微信版本符合要求首先,确保你的华为手机系统版本已更新到最新版本,以及微信App

掌握Golang如何实现游戏开发的可能性 掌握Golang如何实现游戏开发的可能性 Mar 16, 2024 pm 12:57 PM

在当今的软件开发领域中,Golang(Go语言)作为一种高效、简洁、并发性强的编程语言,越来越受到开发者的青睐。其丰富的标准库和高效的并发特性使它成为游戏开发领域的一个备受关注的选择。本文将探讨如何利用Golang来实现游戏开发,并通过具体的代码示例来展示其强大的可能性。1.Golang在游戏开发中的优势作为一种静态类型语言,Golang在构建大型游戏系统

如何在Golang中实现精确除法运算 如何在Golang中实现精确除法运算 Feb 20, 2024 pm 10:51 PM

在Golang中实现精确除法运算是一个常见的需求,特别是在涉及金融计算或其它需要高精度计算的场景中。Golang的内置的除法运算符“/”是针对浮点数计算的,并且有时会出现精度丢失的问题。为了解决这个问题,我们可以借助第三方库或自定义函数来实现精确除法运算。一种常见的方法是使用math/big包中的Rat类型,它提供了分数的表示形式,可以用来实现精确的除法运算

PHP游戏需求实现指南 PHP游戏需求实现指南 Mar 11, 2024 am 08:45 AM

PHP游戏需求实现指南随着互联网的普及和发展,网页游戏的市场也越来越火爆。许多开发者希望利用PHP语言来开发自己的网页游戏,而实现游戏需求是其中一个关键步骤。本文将介绍如何利用PHP语言来实现常见的游戏需求,并提供具体的代码示例。1.创建游戏角色在网页游戏中,游戏角色是非常重要的元素。我们需要定义游戏角色的属性,比如姓名、等级、经验值等,并提供方法来操作这些

使用PHP实现SaaS:全面解析 使用PHP实现SaaS:全面解析 Mar 07, 2024 pm 10:18 PM

实在抱歉,我无法提供实时的编程指导,但我可以为你提供一篇代码示例,让你更好地理解如何使用PHP实现SaaS。以下是一篇1500字以内的文章,标题为《使用PHP实现SaaS:全面解析》。在当今信息时代,SaaS(SoftwareasaService)已经成为了企业和个人使用软件的主流方式,它提供了更灵活、更便捷的软件访问方式。通过SaaS,用户无需在本地

利用Golang实现数据导出功能详解 利用Golang实现数据导出功能详解 Feb 28, 2024 pm 01:42 PM

标题:利用Golang实现数据导出功能详解随着信息化程度的提升,很多企业和组织需要将存储在数据库中的数据导出到不同的格式中,以便进行数据分析、报表生成等用途。本文将介绍如何利用Golang编程语言实现数据导出功能,包括连接数据库、查询数据和导出数据到文件的详细步骤,并提供具体的代码示例。连接数据库首先,我们需要使用Golang中提供的数据库驱动程序,比如da

See all articles