이 기사는 모듈식 프로그래밍 사양, CommonJS, AMD, CMD 및 ES6 관련 문제를 주로 소개하는 javascript에 대한 관련 지식을 제공하는 것이 모든 사람에게 도움이 되기를 바랍니다.
관련 권장사항: javascript 학습 튜토리얼
AMD, CMD, CommonJs
는 ES5
에서 제공되는 모듈형 프로그래밍 솔루션입니다. >import/export는 ES6
의 새로운 모듈형 프로그래밍 솔루션입니다. AMD、CMD、CommonJs
是ES5
中提供的模块化编程方案,import/export
是ES6
中新增的模块化编程方案。
那么,究竟什么什么是AMD、CMD、CommonJs
?他们之间又存在什么区别呢?项目开发应该选用哪种模块化编程规范,又是如何使用?本篇博文将一一解答以上疑问。
AMD
是”Asynchronous Module Definition
”的缩写,即”异步模块定义”。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。
这里异步指的是不堵塞浏览器其他任务(dom
构建,css
渲染等),而加载内部是同步的(加载完模块后立即执行回调)。
RequireJS
:是一个AMD
框架,可以异步加载JS
文件,按照模块加载方法,通过define()函数定义,第一个参数是一个数组,里面定义一些需要依赖的包,第二个参数是一个回调函数,通过变量来引用模块里面的方法,最后通过return来输出。
AMD
是RequireJS
在推广过程中对模块定义的规范化产出,它是一个概念,RequireJS
是对这个概念的实现,就好比JavaScript
语言是对ECMAScript
规范的实现。AMD
是一个组织,RequireJS
是在这个组织下自定义的一套脚本语言。
不同于CommonJS
,它要求两个参数:
require([module], callback);
第一个参数[module]
,是一个数组,里面的成员是要加载的模块,callback
是加载完成后的回调函数。如果将上述的代码改成AMD
方式:
require(['math'], function(math) { math.add(2, 3);})
其中,回调函数中参数对应数组中的成员(模块)。
requireJS
加载模块,采用的是AMD
规范。也就是说,模块必须按照AMD
规定的方式来写。
具体来说,就是模块书写必须使用特定的define()
函数来定义。如果一个模块不依赖其他模块,那么可以直接写在define()
函数之中。
define(id, dependencies, factory);
id
:模块的名字,如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本名字;dependencies
:模块的依赖,已被模块定义的模块标识的数组字面量。依赖参数是可选的,如果忽略此参数,它应该默认为["require", "exports", "module"]
。然而,如果工厂方法的长度属性小于3,加载器会选择以函数的长度属性指定的参数个数调用工厂方法。factory
:模块的工厂函数,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值。
假定现在有一个math.js
文件,定义了一个math
模块。那么,math.js
书写方式如下:
// math.jsdefine(function() { var add = function(x, y) { return x + y; } return { add: add }})
加载方法如下:
// main.jsrequire(['math'], function(math) { alert(math.add(1, 1));})
如果math
模块还依赖其他模块,写法如下:
// math.jsdefine(['dependenceModule'], function(dependenceModule) { // ...})
当require()
函数加载math
模块的时候,就会先加载dependenceModule
模块。当有多个依赖时,就将所有的依赖都写在define()
函数第一个参数数组中,所以说AMD
是依赖前置的。这不同于CMD
规范,它是依赖就近的。
CMD
CMD
即Common Module Definition
通用模块定义,是SeaJS
在推广过程中对模块定义的规范化产出,是一个同步模块定义,是SeaJS
的一个标准,SeaJS
是CMD
概念的一个实现,SeaJS
是淘宝团队玉伯提供的一个模块开发的js
框架。CMD
规范是国内发展出来的,就像AMD
有个requireJS
,CMD
有个浏览器的实现SeaJS
,SeaJS
要解决的问题和requireJS
AMD, CMD, CommonJs
는 정확히 무엇인가요? 그들 사이의 차이점은 무엇입니까? 프로젝트 개발에는 어떤 모듈형 프로그래밍 사양을 사용해야 하며 어떻게 사용합니까? 이번 블로그 포스팅에서는 위의 질문에 대해 하나씩 답변해드리겠습니다. 🎜🎜2. AMD-Asynchronous Module Definition🎜🎜AMD
는 "Asynchronous Module Definition
"의 약어, 즉 "Asynchronous Module Definition"입니다. ". 모듈을 비동기적으로 로드하며, 모듈 로드는 후속 명령문의 실행에 영향을 주지 않습니다. 🎜🎜여기서 비동기란 브라우저의 다른 작업(dom
구성, css
렌더링 등)을 차단하지 않는 것을 의미하며, 로드는 내부적으로 동기적입니다(콜백은 로드 후 즉시 실행됩니다) 모듈)). 🎜🎜🎜RequireJS
:JS
파일을 비동기적으로 로드할 수 있는AMD
프레임워크이며, 다음과 같이 정의() 함수를 통해 정의됩니다. 모듈 로딩 메소드의 첫 번째 매개변수는 일부 종속 패키지를 정의하는 배열이고, 두 번째 매개변수는 변수를 통해 모듈의 메소드를 참조하고 마지막으로 return을 통해 출력되는 콜백 함수입니다. 🎜
AMD
는 RequireJS
의 승격 프로세스 중 표준화된 모듈 정의 출력이며, RequireJS
는 a 이 개념의 구현은 JavaScript
언어가 ECMAScript
사양을 구현하는 것과 같습니다. AMD
는 조직이고, RequireJS
는 이 조직에서 맞춤화된 스크립트 언어 세트입니다. 🎜🎜CommonJS
와는 달리 두 개의 매개변수가 필요합니다. 🎜define(function(require, exports, module) { // 模块代码});
[module]
는 배열이고, 그 안에 있는 멤버는 로드할 모듈입니다. code>callback은 로딩이 완료된 후의 콜백 함수입니다. 위 코드를 AMD
메소드로 변경하면: 🎜// CMDdefine(function(require, exports, module) { var a = require('./a') a.doSomething() // 此处略去 100 行 var b = require('./b') // 依赖可以就近书写 b.doSomething() // ... })// AMD 默认推荐的是define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好 a.doSomething() // 此处略去 100 行 b.doSomething() ...})
requireJS
는 AMD
사양을 사용하여 모듈을 로드합니다. 즉, 모듈은 AMD
에서 지정한 방식으로 작성되어야 합니다. 🎜🎜구체적으로 모듈 작성은 특정 define()
함수를 사용하여 정의해야 합니다. 모듈이 다른 모듈에 의존하지 않는 경우 define()
함수에 직접 작성할 수 있습니다. 🎜var math = require('math');
🎜이제
id
: 모듈 이름. 이 매개변수가 제공되지 않으면 모듈 이름은 기본적으로 모듈 로더가 요청한 지정된 스크립트 이름이어야 합니다. /li>종속성
: 모듈 종속성, 모듈에 의해 정의된 모듈로 식별되는 배열 리터럴입니다. 종속성 매개변수는 선택사항입니다. 생략할 경우 기본값은["require", "exports", "module"]
입니다. 그러나 팩토리 메소드의 길이 속성이 3보다 작으면 로더는 함수의 길이 속성에 지정된 개수의 인수를 사용하여 팩토리 메소드를 호출하도록 선택합니다.factory
: 모듈의 팩토리 함수, 모듈 초기화 중에 실행될 함수 또는 객체입니다. 함수라면 한 번만 실행되어야 합니다. 객체인 경우 이 객체는 모듈의 출력 값이어야 합니다.
math
모듈을 정의하는 math.js
파일이 있다고 가정해 보겠습니다. 그러면 math.js
는 다음과 같이 작성됩니다. 🎜var math = require('math');math.add(2,3); // 5
module exports require global
math
모듈도 다른 모듈에 의존하는 경우에는 다음과 같이 작성됩니다. 🎜var module = { exports: {}};(function(module, exports) { exports.multiply = function (n) { return n * 1000 }; }(module, module.exports))var f = module.exports.multiply; f(5) // 5000
require()
함수가 math
모듈을 로드할 때 dependentModule
모듈을 먼저 로드합니다. 여러 종속성이 있는 경우 모든 종속성은 define()
함수의 첫 번째 매개변수 배열에 기록되므로 AMD
는 사전 종속적입니다. 이는 근접성에 의존하는 CMD
사양과 다릅니다. 🎜 CMD🎜🎜3. CMD - 동기화 모듈 정의🎜🎜CMD
는 SeaJS
의 정의인 Common Module Definition
공통 모듈 정의입니다. 모듈 정의의 표준화된 출력은 SeaJS
의 표준인 동기화된 모듈 정의입니다. SeaJS
는 CMD.<code>SeaJS
는 Taobao 팀 Yubo에서 제공하는 모듈로 개발된 js
프레임워크입니다. CMD
사양은 AMD
에 requireJS
가 있고 CMD
에 브라우저 구현이 있는 것처럼 국내에서 개발되었습니다. code>SeaJS, SeaJS
는 requireJS
와 동일한 문제를 해결하지만, 모듈 정의 방법 및 모듈 로딩 측면에서 (실행, 구문 분석이라고 할 수 있음) 타이밍에 차이가 있습니다. 🎜CMD
通过define()
定义,没有依赖前置,通过require
加载jQuery
插件,CMD
是依赖就近,在什么地方使用到插件就在什么地方require
该插件,即用即返,这是一个同步的概念。
在 CMD
规范中,一个模块就是一个文件。代码的书写格式如下:
define(function(require, exports, module) { // 模块代码});
其中,
require
是可以把其他模块导入进来的一个参数;exports
是可以把模块内的一些属性和方法导出的;module
是一个对象,上面存储了与当前模块相关联的一些属性和方法。
AMD
是依赖关系前置,在定义模块的时候就要声明其依赖的模块;CMD
是按需加载依赖就近,只有在用到某个模块的时候再去require
,示例代码如下:
// CMDdefine(function(require, exports, module) { var a = require('./a') a.doSomething() // 此处略去 100 行 var b = require('./b') // 依赖可以就近书写 b.doSomething() // ... })// AMD 默认推荐的是define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好 a.doSomething() // 此处略去 100 行 b.doSomething() ...})
CommonJS
规范是通过module.exports
定义的,在前端浏览器里面并不支持module.exports
,通过node.js
后端使用。Nodejs
端使用CommonJS
规范,前端浏览器一般使用AMD
、CMD
、ES6
等定义模块化开发规范。
CommonJS
的终极目标是提供一个类似Python
,Ruby
和Java
的标准库。这样的话,开发者可以使用CommonJS API
编写应用程序,然后这些应用就可以运行在不同的JavaScript
解释器和不同的主机环境中。
在兼容CommonJS
的系统中,你可以使用JavaScript
开发以下程序:
- 服务器端
JavaScript
应用程序;- 命令行工具;
- 图形界面应用程序;
- 混合应用程序(如,Titanium或Adobe AIR);
2009年,美国程序员Ryan Dahl创造了node.js
项目,将javascript
语言用于服务器端编程。这标志"Javascript
模块化编程"正式诞生。NodeJS
是CommonJS
规范的实现,webpack
也是以CommonJS
的形式来书写。
node.js
的模块系统,就是参照CommonJS
规范实现的。在CommonJS
中,有一个全局性方法require()
,用于加载模块。假定有一个数学模块math.js
,就可以像下面这样加载。
var math = require('math');
然后,就可以调用模块提供的方法:
var math = require('math');math.add(2,3); // 5
CommonJS
定义的模块分为:模块引用(require)、 模块定义(exports)、模块标识(module)。
其中,
require()
用来引入外部模块;exports
对象用于导出当前模块的方法或变量,唯一的导出口;module
对象就代表模块本身。
虽说NodeJS
遵循CommonJS
的规范,但是相比也是做了一些取舍,添了一些新东西的。
NPM
作为Node
包管理器,同样遵循CommonJS
规范。
下面讲讲commonJS
的原理以及简易实现:
1、原理
浏览器不兼容CommonJS
的根本原因,在于缺少四个Node.js
环境变量。
module exports require global
只要能够提供这四个变量,浏览器就能加载 CommonJS
模块。
下面是一个简单的示例。
var module = { exports: {}};(function(module, exports) { exports.multiply = function (n) { return n * 1000 }; }(module, module.exports))var f = module.exports.multiply; f(5) // 5000
上面代码向一个立即执行函数提供 module 和 exports 两个外部变量,模块就放在这个立即执行函数里面。模块的输出值放在 module.exports 之中,这样就实现了模块的加载。
2、Browserify 的实现Browserify
是目前最常用的 CommonJS
格式转换工具。
请看一个例子,main.js
模块加载 foo.js
模块。
// foo.jsmodule.exports = function(x) { console.log(x);};// main.jsvar foo = require("./foo");foo("Hi");
使用下面的命令,就能将main.js
转为浏览器可用的格式。
$ browserify main.js > compiled.js
其中,Browserify
到底做了什么?安装一下browser-unpack
,就清楚了。
$ npm install browser-unpack -g
然后,将前面生成的compile.js解包。
$ browser-unpack < compiled.js
[ { "id":1, "source":"module.exports = function(x) {\n console.log(x);\n};", "deps":{} }, { "id":2, "source":"var foo = require(\"./foo\");\nfoo(\"Hi\");", "deps":{"./foo":1}, "entry":true }]
可以看到,browerify
将所有模块放入一个数组,id
属性是模块的编号,source
属性是模块的源码,deps
属性是模块的依赖。
因为 main.js
里面加载了 foo.js
,所以 deps
属性就指定 ./foo
对应1号模块。执行的时候,浏览器遇到 require('./foo')
语句,就自动执行1号模块的 source
属性,并将执行后的 module.exports
属性值输出。
有关es6
模块特性,强烈推荐阮一峰老师的:ECMAScript 6 入门 - Module 的语法专栏。
要说 ES6
模块特性,那么就先说说 ES6
模块跟 CommonJS
模块的不同之处。
ES6
模块输出的是值的引用,输出接口动态绑定,而CommonJS
输出的是值的拷贝;ES6
模块编译时执行,而CommonJS
模块总是在运行时加载。
CommonJS
模块输出的是值的拷贝(原始值的拷贝),也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
// a.jsvar b = require('./b');console.log(b.foo);setTimeout(() => { console.log(b.foo); console.log(require('./b').foo);}, 1000);// b.jslet foo = 1;setTimeout(() => { foo = 2;}, 500);module.exports = { foo: foo,};// 执行:node a.js// 执行结果:// 1// 1// 1
上面代码说明,b 模块加载以后,它的内部 foo 变化就影响不到输出的 exports.foo 了。这是因为 foo 是一个原始类型的值,会被缓存。所以如果你想要在 CommonJS
中动态获取模块中的值,那么就需要借助于函数延时执行的特性。
// a.jsvar b = require('./b');console.log(b.foo);setTimeout(() => { console.log(b.foo); console.log(require('./b').foo);}, 1000);// b.jsmodule.exports.foo = 1; // 同 exports.foo = 1 setTimeout(() => { module.exports.foo = 2;}, 500);// 执行:node a.js// 执行结果:// 1// 2// 2
所以我们可以总结一下:
CommonJS
模块重复引入的模块并不会重复执行,再次获取模块直接获得暴露的module.exports
对象。- 如果你需要处处获取到模块内的最新值的话,也可以每次更新数据的时候每次都要去更新
module.exports
上的值- 如果暴露的
module.exports
的属性是个对象,那就不存在这个问题了。
相关推荐:javascript视频教程
위 내용은 JavaScript 모듈형 프로그래밍 사양 CommonJS, AMD, CMD, ES6의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!