commonJS、AMD、ES6模块使用规范

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

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

###使用

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

b.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的加载

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

  <script src="js/require.js"></script>  

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

  <script src="js/require.js" defer async="true" ></script>

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

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

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

####主模块

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

####require.config()方法

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

上面的代码给出了三个模块的文件名,路径默认与main.js在同一个目录(js子目录)。如果这些模块在其他目录,比如js/lib目录,则有两种写法。一种是逐一指定路径。

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

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

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”
    }
  });
```

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

例如:

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

  return  {
    config: config
  }
})
AMD模块的写法

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

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

      // 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()函数的第一个参数,必须是一个数组,指明该模块的依赖性。

 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 导出该模块要导出的变量、函数、对象等等。
export const color = '#fff';
  • as 输出时创建别名,也适用于导入情况。
const color = '#fff';
export color as white
  • export default 该模块的默认输出值,可以为变量、函数、对象,一个模块只能导出一个默认值。默认导出的内容可以无名称,因为默认导出就代表该模块,但也可以有名称,或者使用别名 as。
 export default const color = '#fff';
// export default 5;
// const color = ‘#fff’;
// export { color as default  };
使用

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

  • 导入非默认内容,需要用结构的方式,因为在模块中,非默认导出的内容,都会被添加到一个变量中,用解构的方式拿出一个或多个内容。
import { color } from './color';
  • 导入默认内容,可以直接导出即可。
import color from './color';
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值