Javascript的模块化编程
2016-04-08 13:54
330 查看
Javascript在设计之初并没有提供一种原生的,语言级别的模块化方式来组织代码,比如Java语言通过package和import来管理和使用模块。ECMAScript 6引入了class和import的概念来支持模块化,但是浏览器全面支持这个标准还需要很长时间。
应用程序的模块化指的就是通过一些高度解耦的,存放在不同地方的功能模块构成。近年来随着Javascript应用的复杂化,大型化,Javascript代码需要更为有序的组织,在Javascript社区出现了很多种模块化的实现方式,最主要的两个规范是CommomJS和AMD,本文会重点阐述这两个规范。
CommonJS对于模块的定义非常简单,分为模块定义(exports),模块引用(require),模块标示三部分。
通过全局变量 exports 返回当前模块希望提供给其他模块的对象:
通过全局函数 require 来导入其他模块的输出:
模块标示其实就是传递给require方法的参数,用来指定加载文件路径,可以没有后缀名.js,例如上面例子中的 “./foobar”。
CommonJS模块的代码都运行在模块作用域,不会污染全局作用域,模块可以多次加载,但是结果会被缓存。CommonJS主要是为服务器端JavaScript运行库设计的,模块是同步加载的,这使得难以在浏览器中运行CommonJS代码。Node.js上面有一些项目例如Browserify,将CommonJS带进了浏览器,Browserify将依赖到的单独的js文件打包成一个单独的js文件,统一加载到浏览器端。
模块通过 define 函数定义在闭包中,格式如下:
id 是模块的名字,它是可选的参数。dependencies 指定了所要依赖的模块列表,它是一个数组,也是可选的参数,每个依赖的模块的输出将作为参数一次传入 factory 中。factory 是最后一个参数,它包裹了模块的具体实现,它是一个函数或者对象。如果是函数,那么它的返回值就是模块的输出接口或值。
定义一个名为 myModule 的模块,它依赖 foo, bar 模块:
定义一个独立模块,不需要依赖任何其他模块:
通过 require 调用模块:
在模块定义内部也可以使用require来加载其他模块:
上面的例子中 foo 和 bar没有加载完成之前,isReady属性为 false。
目前主要有两个Javascript库实现了AMD规范:require.js和curl.js。RequireJS由James Burke创建,他也是AMD规范的创始人。
由于当前版本的Javascript没有提供原生的模块化支持,社区的开发者进行了很多模块化的探索,使得Javascript工程化成为了可能,CommonJS和AMD就是最主要的两个规范。
应用程序的模块化指的就是通过一些高度解耦的,存放在不同地方的功能模块构成。近年来随着Javascript应用的复杂化,大型化,Javascript代码需要更为有序的组织,在Javascript社区出现了很多种模块化的实现方式,最主要的两个规范是CommomJS和AMD,本文会重点阐述这两个规范。
1. CommonJS
CommonJS是以在浏览器之外构建Javascript系统而产生的项目,致力于Javascript模块的标准化工作。主要特点是同步加载Javascript模块,运行在服务器端。Node.js 就是CommonJS规范的一个实现。CommonJS对于模块的定义非常简单,分为模块定义(exports),模块引用(require),模块标示三部分。
通过全局变量 exports 返回当前模块希望提供给其他模块的对象:
// 定义行为 function foobar(){ this.foo = function(){ console.log('Hello foo'); } this.bar = function(){ console.log('Hello bar'); } } // 把 foobar 暴露给其它模块 exports.foobar = foobar;
通过全局函数 require 来导入其他模块的输出:
//使用文件与模块文件在同一目录 var foobar = require('./foobar').foobar, test = new foobar(); test.bar(); // 'Hello bar'
模块标示其实就是传递给require方法的参数,用来指定加载文件路径,可以没有后缀名.js,例如上面例子中的 “./foobar”。
CommonJS模块的代码都运行在模块作用域,不会污染全局作用域,模块可以多次加载,但是结果会被缓存。CommonJS主要是为服务器端JavaScript运行库设计的,模块是同步加载的,这使得难以在浏览器中运行CommonJS代码。Node.js上面有一些项目例如Browserify,将CommonJS带进了浏览器,Browserify将依赖到的单独的js文件打包成一个单独的js文件,统一加载到浏览器端。
2. AMD
AMD(异步模块定义)是为浏览器环境设计的,采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。模块通过 define 函数定义在闭包中,格式如下:
define(id?: String /*可选*/, dependencies?: String /*可选*/, factory: Function|Object /*用来初始化模块或对象的函数*/);
id 是模块的名字,它是可选的参数。dependencies 指定了所要依赖的模块列表,它是一个数组,也是可选的参数,每个依赖的模块的输出将作为参数一次传入 factory 中。factory 是最后一个参数,它包裹了模块的具体实现,它是一个函数或者对象。如果是函数,那么它的返回值就是模块的输出接口或值。
定义一个名为 myModule 的模块,它依赖 foo, bar 模块:
define('myModule', // 依赖 ['foo', 'bar'], // 依赖(foo 和 bar)被映射为函数的参数 function ( foo, bar ) { // 返回一个定义了模块导出接口的值 // 在这里创建模块 var myModule = { doSomething:function(){ } } return myModule; });
定义一个独立模块,不需要依赖任何其他模块:
define(function () { return { doSomething: function() {} }; });
通过 require 调用模块:
require(['foo', 'bar'], function ( foo, bar ) { foo.doSomething(); });
在模块定义内部也可以使用require来加载其他模块:
define(function ( require ) { var isReady = false, foobar; require(['foo', 'bar'], function (foo, bar) { isReady = true; foobar = foo() + bar(); }); return { isReady: isReady, foobar: foobar }; });
上面的例子中 foo 和 bar没有加载完成之前,isReady属性为 false。
目前主要有两个Javascript库实现了AMD规范:require.js和curl.js。RequireJS由James Burke创建,他也是AMD规范的创始人。
3. 结语
CommonJS 则采用了服务器优先的策略,使用同步方式加载模块,而且试图涵盖更多更宽泛的东西,例如文件IO,Promise等等。而AMD 采取了一种浏览器优先的方式来开发,使用异步方式加载模块。它支持对象、函数、构造器、字符串、JSON 以及其它许多类型的模块,运行在浏览器本地环境之中。由于当前版本的Javascript没有提供原生的模块化支持,社区的开发者进行了很多模块化的探索,使得Javascript工程化成为了可能,CommonJS和AMD就是最主要的两个规范。
相关文章推荐
- JavaScript图解继承(多图)
- window.event.keyCode - 兼容chrom和Firefox
- js日期格式化
- json跨域(2)----js跨域及解决方案
- js 格式化时间(显示格式为:yyyy-mm-dd hh:mi:ss)
- js文件中引用其他js文件
- js 跨域访问实例
- 七牛图片上传JSSDK
- Javascript的动态增加‘类’的方法
- 常见js 函数集合总结
- js五子棋(带AI)
- 笔记练习:《Javascript入门经典(第5版)》page89_7.9_Practice
- 了解ASP.NET MVC几种ActionResult的本质:JavaScriptResult & JsonResult
- JSTL 将double值保留小数点后两位
- 【Javascript下载文件的Post实现】
- js 如何获取一周前当前时间
- JS 加密 _秒解密 packer加密过的js
- 苹果3元一个,鸭梨2元一个,桃子1元一个。现在想用200元买100个水果,在控制台中列出所有可能性。
- js自定义对象和类
- 用原生js实现数字自相加