四时宝库

程序员的知识宝库

干货丨commonJS、AMD、ES6模块使用规范


在早期的时候,只有浏览器环境,JavaScript 代码比较习惯于通过<script></script>标记来实现的,不管是内联还是外联。

这是我开始学 JavaScript 时的做法。我相信大多数 JavaScript 开发者在其生命里至少这样做过一次。

这是开始的好方法。不需要操心外部文件或者依赖。但是这也导致了不可维护的代码,因为:

· 缺乏依赖解析:你必须保证 main 函数之前就有 add、reduce 和 sum 函数。

· 命名空间污染:所有的函数的变量将都驻留在全局作用域。

commonJS:

在 2009 年,出现了关于将 JavaScript 带到服务器端的讨论,因而 ServerJS 诞生了。之后,ServerJS 更名为 CommonJS。

CommonJS 并非一个 JavaScript 库,而是一个标准化组织,像 ECMA 或者 W3C 一样。

ECMA 定义了 JavaScript 语言规范。

W3C 定义了 JavaScript Web API,比如 DOM 和 DOM 事件。CommonJS 的目标是为 Web服务器、桌面和命令行应用程序定义一套通用的 API。

CommonJS 还定义了模块 API 。

因为在服务器应用程序中没有 HTML 页面,也没有 script 标记,所以就得有一些清晰的模块API。

模块需要暴露(export)给其它模块使用,并且是可访问的(import)。

这就是:

同步模块加载 NodeJS,也就是服务器端广泛使用的一种模块化机制,因为模块一般都存在于本地,不需要考虑网络加载因素,所以为同步加载。

commonJS一般在node.js中使用,规范将每一个js文件看成是一个模块,所以,nodejs会为每一个js文件生成一个module对象。

这个module对象会有一个exports属性,并且这个exports属性是一个空对象,即module={ exports:{} },我们这行代码,是给了module对象中export属性赋值的过程)这样即可将config这个变量作为一个公共的输出。

在b.js中如果我们想要用a.js中config这个变量,我们可以在b.js中用下面的代码来引用变config:var config=require('路径/a.js').config.

模块的定义

每一个js文件看成是一个模块,每个模块都有自己独立的作用域,不同模块间变量互不影响。每个js文件中的module变量代表当前模块。

导出

导出时,要求模块化的导出必须是module.exports,这样导出对外的变量或者接口。

a.js

js var config = 10; moduel.exportds = {config};

使用

通过require() 来导入想要使用的其他模块对外导出的变量或者接口;

b.js

js var aModuel = require('路径/a.js'); var aConfig = aModuel.config; console.log(aConfig);//10

require的引入分为三种:

· 如果参数字符串以 / 开头,则表示加载的是一个位于绝对路径的模块文件。

· 如果参数字符串以 ./ 或者../开头,则表示加载的是一个位于相对路径的模块文件

· 如果参数字符串不以 ./ 或 / 开头,则表示加载的是一个默认提供的核心模块(node核心模块,或者通过全局安装或局部安装在node_modules目录中的模块)

AMD:

CommonJS 风格的模块定义的问题是,它不是异步的。

当调用var add=require('add');时,系统会暂停,直到模块准备好了。

这意味着在所有模块正在加载时,这行代码会冻结浏览器。

所以这可能不是定义浏览器端模块的最佳方式。

为了把服务器端用的模块语法转换给浏览器端用,CommonJS 提出了几种模块格式。其中之一,即 "Module/Transfer/C",后来成为异步模块定义(AMD)。

异步模块定义 ,为浏览器环境设计,RequireJS即为遵循AMD规范的模块化工具,requireJS的基本思想是,通过define方法定义模块化,通过require加载模块。使用时要先下载并引入require.js文件。

模块的定义和使用:

require.js的加载

第一步,去官网下载最新版本,直接放到页面进行加载

加载这个文件可能会导致网页失去响应,可以将它放到页面的底部加载,也可以这样写

async属性表明这个文件需要异步加载,避免网页失去响应。IE不支持这个属性,只支持defer,所以把defer也写上。

加载require.js以后,下一步就要加载我们自己的代码了,也就是入口,可以叫主模块,如果文件名叫main.js,写成下面这样就可以了:

<script src="js/require.js" data-main="js/main"> .js后缀可以省略

主模块

js //如果主模块依赖于jQuery可以这样写 require(['jquery'], function ($){ alert($); });

require.config()方法

js require.config({ paths: { "jquery": "jquery.min", "underscore": "underscore.min", "backbone": "backbone.min" } });

上面的代码给出了三个模块的文件名,路径默认与main.js在同一个目录(js子目录)。

如果这些模块在其他目录,比如js/lib目录,则有两种写法。一种是逐一指定路径。

js require.config({ paths: { "jquery": "**lib/**jquery.min", "underscore": "**lib/**underscore.min", "backbone": "**lib/**backbone.min" } });

另一种则是直接改变基目录(baseUrl)。

js require.config({ baseUrl: "js/lib", paths: { "jquery": "jquery.min", "underscore": "underscore.min", "backbone": "backbone.min" } });

如果某个模块在另一台主机上,也可以直接指定它的网址,比如

```js

require.config({ paths: { "jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min" } }); ```

js define(['module1','module2'], function(module1, module2) {//其中module1,module2为顺序依赖项 ... return { // 返回的接口 } })

例如:

```js define(["aa"],function(aa) {//依赖aa并向外导出config var config = 10 + aa

return { config: config } }) ```

AMD模块的写法

require.js加载的模块,采用AMD规范。也就是说,模块必须按照AMD的规定来写。

具体来说,就是模块必须采用特定的define()函数来定义。如果一个模块不依赖其他模块,那么可以直接定义在define()函数之中。

js // math.js define(function (){ var add = function (x,y){ return x+y; }; return { add: add }; }); 加载方法如下: // main.js require(['math'], function (math){ alert(math.add(1,1)); });

如果这个模块还依赖其他模块,那么define()函数的第一个参数,必须是一个数组,指明该模块的依赖性。

js define(['myLib'], function(myLib){ function foo(){ myLib.doSomething(); } return { //返回模块中的函数 foo : foo }; });

当require()函数加载上面这个模块的时候,就会先加载myLib.js文件。

ES6模块

JavaScript 全局模块对象、CommonJS、AMD 和 UMD,太多选择了。现在也许你会问,下一个项目我该用哪一个呢?答案是一个都不用。

JavaScript 语言中并没有内置模块系统。这正是我们有如此多输入和输出模块的不同方式的原因。但是这种情况最近得到改变了。在 ES 6 规范中,模块已经成为 JavaScript 的一部分。所以这个问题的答案是,如果想让项目不会过时,就得用 ES 6 模块语法。

如果使用es6语法,那么则无需引入requireJS进行模块化,它的特点主要为:

· 在模块顶级作用域中的this为undefine。

· 单个文件为一个模块,顶级作用域声明的变量只在当前模块生效。对其他模块不影响,

· 对外导出的变量才能被其他变量使用

· ES6 的模块自动采用严格模式,不管有没有在模块头部加上"use strict";。

定义

导出内容有两种关键字:

· export 导出该模块要导出的变量、函数、对象等等。

js export const color = '#fff';

· as 输出时创建别名,也适用于导入情况。

js const color = '#fff'; export color as white

· export default 该模块的默认输出值,可以为变量、函数、对象,一个模块只能导出一个默认值。默认导出的内容可以无名称,因为默认导出就代表该模块,但也可以有名称,或者使用别名as。

js export default const color = '#fff'; // export default 5; // const color = ‘#fff’; // export { color as default };

使用

在模块中使用import关键字来导出其他模块导出的内容。 分为几种情况:

· 导入非默认内容,需要用结构的方式,因为在模块中,非默认导出的内容,都会被添加到一个变量中,用结构的方式拿出一个或多个内容。

js import { color } from './color';

· 导入默认内容,可以直接导出即可。

js import color from './color';

以上就是今天的分享啦~

如果大家有问题或者想了解更多的

技术干货可以私信发送【微信】加朗妹儿微信哟~

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接