在早期的时候,只有浏览器环境,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';
以上就是今天的分享啦~
如果大家有问题或者想了解更多的
技术干货可以私信发送【微信】加朗妹儿微信哟~