Home >Web Front-end >JS Tutorial >In-depth understanding of the modularization of JavaScript

In-depth understanding of the modularization of JavaScript

黄舟
黄舟Original
2017-03-24 14:56:281425browse

Modularization is very important in projects. A complex project must have many similar functional modules. If you need to rewrite the modules every time, it will definitely be time-consuming and labor-intensive. However, the prerequisite for quoting others to write modules is to have a unified "opening posture". If everyone has their own way of writing, it will definitely be chaotic. Here are several JS modular specifications.

Modularization is very important in projects. A complex project must have many similar functional modules. If you need to rewrite the modules every time, it will definitely be time-consuming and labor-intensive. However, the prerequisite for quoting others to write modules is to have a unified "opening posture". If everyone has their own way of writing, it will definitely be chaotic. Here are several JS modular specifications.

1: Modular process one: script tag

This is the most original JavaScript file loading method. If each file is regarded as is a module, then their interfaces are usually exposed in the global scope, that is, defined in window Object. The interface calls of different modules are all in the same scope. Some complex frameworks will use The concept of namespace is used to organize the interfaces of these modules.

Disadvantages:

1. Pollution of the global scope

2. Developers must subjectively solve the problem of modules and code libraries Dependencies

3. Files can only be loaded in the order in which script tags are written

4. Various resources are difficult to manage in large projects, and long-term accumulated problems lead to chaos in the code base

Two: Modularization Process Two: CommonJS Specification

The core idea of ​​this specification is to allow modules to synchronously load other modules they depend on through the require method , and then export the interfaces that need to be exposed through exports or module.exports.

require("module");
require("../file.js");
exports.doStuff = function(){};
module.exports = someValue;

Advantages:

1. Simple and easy to use

2. Server-side modules are easy to reuse

Disadvantages:

1. The synchronous module loading method is not suitable in the browser environment. Synchronization means blocking loading, and browser resources are loaded asynchronously.

2. Multiple modules cannot be loaded in parallel without blocking.

The difference between module.exports and exports

1. exports is a reference to module.exports

2. The initial value of module.exports is an empty object {}, so the initial value of exports is also {}

3. require() returns module.exports instead of exports

Exports example:

// app.js
var circle = require('./circle');
console.log(circle.area(4));
// circle.js
exports.area = function(r){
 return r * r * Math.PI;
}

module.exports example:

// app.js
var area = require('./area');
console.log(area(4));
// area.js
module.exports = function(r){
 return r * r * Math.PI;
}

Wrong situation:

// app.js
var area = require('./area');
console.log(area(4));
// area.js
exports = function(r){
 return r * r * Math.PI;
}

is actually exports Overwritten, that is to say, exports points to a new piece of memory (the content is a function that calculates the area of ​​a circle), which means that exports and module.exports no longer point to the same piece of memory, that is to say, at this time exports has no connection with module.exports, which means that the memory pointed to by module.exports has not changed in any way and is still an empty object {}, which means that area.js exports an empty object, so we have Calling area(4) in .js will report the error TypeError: object is not a function.

Summary: When we want the module to export an object, both exports and module.exports can be used (but exports cannot be overwritten as a new one) object), and when we want to export non- object interface, we must and can only override module.exports.

Three: Modularization Process Three: AMD Specification

Since the browser-side modules cannot be loaded synchronously, it will affect the loading and execution of subsequent modules, so AMD ( Asynchronous Module Definition (Asynchronous Module Definition) specification was born.

The AMD standard defines the following two APIs

1. require([module], callback);
2. define(id, [depends], callback);

The require interface is used to load a series of modules, and the define interface is used to define and expose a module.

Example:

define("module", ["dep1", "dep2"], function(d1, d2){
 return someExportedValue;
});
require(["module", "../file"], function(module, file){ /* ... */ });

Advantages:

1. Suitable for asynchronous loading of modules in a browser environment

2. Multiple modules can be loaded in parallel

Disadvantages:

1. Increased development costs, making it difficult to read and write code , the semantics of the module definition method are not smooth

2. It does not conform to the general modular way of thinking and is a compromised implementation

Four: Modularization Process Four: CMD Specification

CMD(Common Module Definition)规范和AMD很相似,尽量保持简单,并与CommonJS和Node.js的 Modules 规范保持了很大的兼容性。在CMD规范中,一个模块就是一个文件。

示例:

define(function(require, exports, module){
 var $ = require('jquery');
 var Spinning = require('./spinning');
 exports.doSomething = ...
 module.exports = ...
})

优点:

1、依赖就近,延迟执行

2、可以很容易在 Node.js 中运行

缺点:

1、依赖 SPM 打包,模块的加载逻辑偏重

AMD和CMD的区别

AMD和CMD起来很相似,但是还是有一些细微的差别,让我们来看一下他们的区别在哪里:

1、对于依赖的模块,AMD是提前执行,CMD是延迟执行。

2、AMD推崇依赖前置;CMD推崇依赖就近,只有在用到某个模块的时候再去require。看代码:

// AMD
define(['./a', './b'], function(a, b){ // 依赖必须一开始就写好
  a.doSomething()  
  // 此处略去 100 行
  b.doSomething()  
  ...
});
// CMD
define(function(require, exports, module){
  var a = require('./a')  
  a.doSomething()  
  // 此处略去 100 行
  var b = require('./b')
  // 依赖可以就近书写
  b.doSomething()
  // ...
});

3、AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。

五:模块化进程五:ES6模块化

EcmaScript6标准增加了JavaScript语言层面的模块体系定义。ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS和AMD模块,都只能在运行时确定这些东西。

在 ES6 中,我们使用export关键字来导出模块,使用import关键字引用模块。需要说明的是,ES6的这套标准和目前的标准没有直接关系,目前也很少有JS引擎能直接支持。因此Babel的做法实际上是将不被支持的import翻译成目前已被支持的require。

尽管目前使用import和require的区别不大(本质上是一回事),但依然强烈推荐使用import关键字,因为一旦JS引擎能够解析ES6的import关键字,整个实现方式就会和目前发生比较大的变化。如果目前就开始使用import关键字,将来代码的改动会非常小。

示例:

import "jquery";
export functiondoStuff(){}
module "localModule" {}

优点:

1、容易进行静态分析

2、面向未来的 EcmaScript 标准

缺点:

1、原生浏览器端还没有实现该标准

2、全新的命令字,新版的 Node.js才支持

The above is the detailed content of In-depth understanding of the modularization of JavaScript. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn