Due to the initial positioning of JS (I did not expect it to be used in overly complex scenarios at the beginning), it does not provide a module system. As applications become more complex, modularization becomes a problem that must be solved. In line with the principle of Feimai's in-depth principles, it is necessary to lift the veil of modularization. This article mainly introduces how modularization in Js is implemented in detail, and introduces the operation of modularization in detail, which has certain reference value. Those who are interested can learn more, I hope it can help everyone.
1. Problems that need to be solved by modularization
To conduct an in-depth analysis of something, it is necessary to look at it with a purpose. The problem to be solved by modularization can be summarized in one sentence
Better organize project code without global pollution
To give a simple chestnut, we now have the following Code:
function doSomething () { const a = 10; const b = 11; const add = function (a + b) { return a + b } add (a + b) }
In real application scenarios, doSomething may need to do many, many things, and the add function may be more complex and can be reused, so we hope to separate the add function into a separate file, then:
// 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;
The purpose of this is obvious, to better organize the project code, notice the require and module.exports in the two files, from the current God's perspective, this comes from CommonJS The keywords in the specification (there will be a chapter dedicated to the specification later) represent import and export respectively. Regardless of the specification, this is actually a problem that needs to be solved on our road to modularization. In addition, although the add module needs to be reused, we do not want to cause global pollution when introducing add
2. How to run the imported module
In the above example, we have The code is split into two module files. How can we implement require so that the code in the example can run normally without causing global pollution?
Ignoring the loading process of the module file code, assuming that require can already read the code string from the module file, then require can be implemented like this
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; }
There are several key points:
1) In order not to cause global pollution, the code string needs to be encapsulated in the form of a closure, and the keyword module.exports should be exported. The module is the only carrier to contact the outside world and needs to be used as a closure. The input parameters of the anonymous function are associated with the context passed by the referrer
2) Use new Function to execute the code string. It is estimated that most students are not familiar with new Function because it is generally There is no need to do this when defining a function. You must know that you can directly create a function using the Function class. The syntax is as follows:
var function_name = new function(arg1, arg2, ..., argN, function_body)
In the above form, each arg is a parameter, and the last parameter is the function body ( code to be executed). These parameters must be strings. In other words, you can use it to execute string code, similar to eval, and compared to eval, you can also pass in the values of certain variables in the string code in the form of parameters
3 ) If you have ever wondered why the standard export keyword is only exports but we use module.exports in actual use (it should be familiar to those who have written Node code), then you can find the answer in this code , if you only use exports to receive context, then reassigning exports will not have any impact on context (the address of the parameter is passed). If you don’t believe it, change the code to the following form and run it again:
Demonstration results
3. Code loading method
solves the problem of running the code, and also needs to solve the problem of loading the module file code. According to the above example, our The goal is to load the module file code in the form of a string
In the Node container, all module files are local. You only need to read the module file from the local disk and load the string code, and then follow the above steps The process is fine. Facts have proved that the loading and execution method of Node's non-built-in, core, and c++ modules is roughly the same (although it is not new Function, it is a similar method)
In the RN/Weex container, you need to load a For remote bundle.js, you can request a remote js file through Native capabilities, and then read it into a string code and load it (according to this logic, it seems that Node can read a remote js module, although in most cases We don’t need to do this next)
In the browser environment, all Js modules need to be read remotely. The embarrassing thing is that, limited by the capabilities provided by the browser, it cannot be streamed through ajax in the form of files. Read the remote js file directly into string code. If the prerequisites cannot be met, the above operation strategy will not work, and we can only find another way
This is why there is a CommonJs specification, and why there are AMD/CMD specifications
So How to do it on the browser? To dynamically load a remote Js module file through Js control in the browser, you need to dynamically insert a <script> node: </script>
// 摘抄自 require.js 的一段代码 var node = config.xhtml ? document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : document.createElement('script'); node.type = config.scriptType || 'text/javascript'; node.charset = 'utf-8'; node.async = true; node.setAttribute('data-requirecontext', context.contextName); node.setAttribute('data-requiremodule', moduleName); node.addEventListener('load', context.onScriptLoad, false); node.addEventListener('error', context.onScriptError, false);
要知道,设置了 <script> 标签的 src 之后,代码一旦下载完成,就会立即执行,根本由不得你再封装成闭包,所以文件模块需要在定义之初就要做文章,这就是我们说熟知的 AMD/CMD 规范中的 define,开篇的 add.js 需要重新改写一下</script>
// add.js 文件 define ('add',function () { function add (a, b) { return a + b; } return add; })
而对于 define 的实现,最重要的就是将 callback 的执行结果注册到 context 的一个模块数组中:
context.modules = {} function define(name, callback) { context.modules[name] = callback && callback() }
于是 require 就可以从 context.modules 中根据模块名载入模块了,是不是有了一种自己去写一个 “requirejs” 的冲动感
具体的 AMD 实现当然还会复杂很多,还需要控制模块载入时序、模块依赖等等,但是了解了这其中的灵魂,想必去精读 require.js 的源码也不是一件困难的事情
四、Webpack 中的模块化
Webpack 也可以配置异步模块,当配置为异步模块的时候,在浏览器环境同样的是基于动态插入 <script> 的方式载入远程模块。在大多数情况下,模块的载入方式都是类似于 Node 的本地磁盘同步载入的方式</script>
嫑忘记,Webpack 除了有模块化的能力,还是一个在辅助完善开发工作流的工具,也就是说,Webpack 的模块化是在开发阶段的完成的,使用 Webpack 构筑的工作环境,在开发阶段虽然是独立的模块文件,但是在运行时,却是一个合并好的文件
所以 Webpack 是一种在非运行时的模块化方案(基于 CommonJs),只有在配置了异步模块的时候对异步模块的加载才是运行时的(基于 AMD)
五、模块化规范
通用的问题在解决的过程中总会形成规范,上文已经多次提到 CommonJs、AMD、CMD,有必要花点篇幅来讲一讲规范
Js 的模块化规范的萌发于将 Js 扩展到后端的想法,要使得 Js 具备类似于 Python、Ruby 和 Java 那样具备开发大型应用的基础能力,模块化规范是必不可少的。CommonJS 规范的提出,为Js 制定了一个美好愿景,希望 Js 能在任何地方运行,包括但不限于:
服务器端 Js 应用
命令行工具
桌面应用
混合应用
CommonJS 对模块的定义并不复杂,主要分为模块引用、模块定义和模块标识
模块引用:使用 require 方法来引入一个模块
模块定义:使用 exports 导出模块对象
模块标识:给 require 方法传入的参数,小驼峰命名的字符串、相对路径或者绝对路径
模块示意
CommonJs 规范在 Node 中大放异彩并且相互促进,但是在浏览器端,鉴于网络的原因,同步的方式加载模块显然不太实用,在经过一段争执之后,AMD 规范最终在前端场景中胜出(全称 Asynchronous Module Definition,即“异步模块定义”)
什么是 AMD,为什么需要 AMD ?在前述模块化实现的推演过程中,你应该能够找到答案
除此之外还有国内玉伯提出的 CMD 规范,AMD 和 CMD 的差异主要是,前者需要在定义之初声明所有的依赖,后者可以在任意时机动态引入模块。CMD 更接近于 CommonJS
两种规范都需要从远程网络中载入模块,不同之处在于,前者是预加载,后者是延迟加载
相关推荐:
javascript高级模块化require.js的具体使用方法实例分享
JavaScript使用高级模块化require.js的具体方法详解
The above is the detailed content of How is modularity implemented in JS?. For more information, please follow other related articles on the PHP Chinese website!

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

Python and JavaScript have their own advantages and disadvantages in terms of community, libraries and resources. 1) The Python community is friendly and suitable for beginners, but the front-end development resources are not as rich as JavaScript. 2) Python is powerful in data science and machine learning libraries, while JavaScript is better in front-end development libraries and frameworks. 3) Both have rich learning resources, but Python is suitable for starting with official documents, while JavaScript is better with MDNWebDocs. The choice should be based on project needs and personal interests.

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

JavaScript's applications in the real world include server-side programming, mobile application development and Internet of Things control: 1. Server-side programming is realized through Node.js, suitable for high concurrent request processing. 2. Mobile application development is carried out through ReactNative and supports cross-platform deployment. 3. Used for IoT device control through Johnny-Five library, suitable for hardware interaction.

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base

JavaScript is the core language of modern web development and is widely used for its diversity and flexibility. 1) Front-end development: build dynamic web pages and single-page applications through DOM operations and modern frameworks (such as React, Vue.js, Angular). 2) Server-side development: Node.js uses a non-blocking I/O model to handle high concurrency and real-time applications. 3) Mobile and desktop application development: cross-platform development is realized through ReactNative and Electron to improve development efficiency.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

Dreamweaver Mac version
Visual web development tools

Safe Exam Browser
Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

SublimeText3 Chinese version
Chinese version, very easy to use

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool