1. CommonJS是什么?
CommonJS也许还是个新生事物,就我接触到的人对它的理解来看,总感觉存在很多的误解,有说它是个框架,有说是规范的,还有说是代码风格的,至于它到底应当是什么,应当它自己老家说的最明白,知子莫若母么,首先引用人家娘家人给它的定义:
JavaScript is a powerful object oriented language with some of the fastest dynamic language interpreters around. The official JavaScript specification defines APIs for some objects that are useful for building browser-based applications. However, the spec does not define a standard library that is useful for building a broader range of applications.
The CommonJS API will fill that gap by defining APIs that handle many common application needs, ultimately providing a standard library as rich as those of Python, Ruby and Java. The intention is that an application developer will be able to write an application using the CommonJS APIs and then run that application across different JavaScript interpreters and host environments.
这娘家人的风格跟在下有点像,欲交代一件事情,必先做好铺垫,说明白为什么需要这个玩意,然后主角隆重登场,灯光,鲜花,美女, action......cut;擦,跑题了; 这段文字比较容易理解了,cet==4的人看明白绝对没问题,之所以这么确定,是因为在下就是一个活生生的例子;这2段话翻译过来就是说:
Javsscript是一种很强大的面向对象的语言,有很多灰常灰常快的解释器实现;(but)官方定义的玩意都跟浏览器结合太紧了,用来搞基于浏览器的应用还成,想搞其他应用就...了,根本就没定义出标准来;
俺们家的CommonJS涅,就填平了这道鸿沟,给定义了好多好多好多普通用应用所需要的接口,都能跟python啊,ruby啊java啊相媲美.搞这玩意的目的就是让开发者能基于这些接口写出的应用能在不同的js解释器或者宿主环境下都能运行.
课本的东西要有消化和吸收,用自己的话来说一遍就是CommonJS是试图给现有的javascript做一个补充,增加一些独立于浏览器的东西定义,这些东西定义出来就是CommonJS api,而定义这些api的详细说明,就是CommonJS的规范,相应的去实现这些api的东西,就是库;所以我们可以说CommonJS就是一组规范定义的接口再加上实现这些接口的库;简单来说就是 CommonJS = spcifications + apis + libs;而我们自己写代码也学CommonJS的样子来,那么在这个意义上来说,CommonJS也可以说是一种代码书写风格;
2. CommonJS规范之Modules详解
目前的CommonJS规范含有3块内容,分别为Modules/Packages/System;对应汉语就是模块/包/系统;分别说明怎么搞一个模块,怎么打一个包,和作为通用的系统接口来说,应当提供什么东西;下面我们关注一下Modules的规范,其他2个的规范请移步http://www.commonjs.org/specs/自己查看吧;
原文就不再引用了,直接上翻译后的;
1. 每个模块里面都应当有个函数叫require;
1.1 require接收模块描述符作为参数
1.2 require的返回值就是那个描述符描述的模块导出(export)的api
1.3 如果存在循环依赖,那么require返回的应当是那个模块在循环依赖产生前已经可以导出的api;
1.4 如果那个模块有问题,要抛出个错误来,就是说别悄没声的装作完事了;要大喊一声你有病啊;
2. 每个模块都应当有个叫exports的变量,好把自己的api都塞进去;
3. 模块必须把exports作为导出api的唯一方法;
再用自己的话来把上面的定义复述一遍,就是引用另一个模块要使用require函数,require呢就只认识exports,把你exports的东西给返回去;如今CommonJS已经有很多的具体实现,最为知名的应当是nodejs啦.他实现了CommonJS规范里面的模块和单元测试部分,另外还有2个非正式的(Promise/B + Promise/D),对这个有兴趣的看官请参考nodejs文档以作更多更深入的了解;另一个实现了CommonJS的就是我们使用的titanium mobile了,其他还有好多不同的实现,在CommonJS网站有列表,或者也可以参考就是维基百科(英文版).
3. Titanium里面的CommonJS实现
我们所使用的Titanium虽然实现了CommonJS规范,但不过并非其的忠实实现,而是自己做了一些扩充,详细的文档请参阅https://wiki.appcelerator.org/display/guides/CommonJS+Modules+in+Titanium , 这里面需要额外说明一下module.exports,从文档中的解释来说这哥们是个对象,是用来导出表示模块内对象的;以在下的理解,titanium mobile里面特意搞这个就是用来区分对象与函数集的;假如一个模块仅仅是需要导出一些接口,那么请使用exports,如果一个模块需要导出一个对象,请使用module.exports;对象与函数集的区别就在于函数集中的各个函数之间不需要有共同需要的变量,尤其是某些状态变量;对象则不同是有自己的数据的,这些数据就表明了这个对象的状态,而对象中的函数,所操作的应当都是本对象的数据;具体到实际的titanium mobile项目中,对于工具类函数集,比如您需要个大小写切换的函数,那么就就写一个exports.convertCase = function(...){...};假如你你需要创建一个窗口(View)啊模型(Model)啊控制器啊(Controller)什么的,请使用module.exports;
4. CommonJS实战
至此理论背景交代完毕,下面进入实战,来看看另一篇博文里面写的mvc例子改为commonjs风格是什么样子;修改后代码如下:
1 //app.js 2 3 var LoginWindow = require('view/login');//object use upper case; 4 var WelcomeWindow = require('view/welcome'); 5 var User = require('model/user'); 6 7 loginWindow = new LoginWindow();//instance use lower case; 8 loginWindow.addEventListener('win:close',function(data){ 9 var user = new user(data.username,data.password); 10 if(user.login()){ 11 loginWindow.close(); 12 welcomeWindow = new WelcomeWindow(); 13 welcomeWindow.open(); 14 }else{ 15 alert('Wrong username or password'); 16 } 17 });
1 //view/login.js 2 3 function LoginWindow(){ 4 ..................... 5 ..................... 6 return win; 7 } 8 9 module.exports = LoginWindow; 10 11 //view/welcome.js 12 13 function WelcomeWindow(){ 14 .......................... 15 .......................... 16 return win; 17 } 18 module.exports = WelcomeWindow; 19 20 //model/user.js 21 Function User(id,name){ 22 .......... 23 .......... 24 } 25 26 User.prototype.login = function(){ 27 .................... 28 } 29 30 module.exports = User;
对照先前代码可以看出,我们只是app.js里面使用view/model的方法略有改变;
而view/model本身的变化,只是在最后增加了一句module.exports = xxxxxx;
上述所说的都是module.exports的使用,另附一个适合exports的简单例子:
1 //lib/util.js 2 3 exports.convertCase = function(string){ 4 ............ 5 return string; 6 } 7 8 exports.getAge = function(birthday){ 9 //Get Age From Date of Birthday; 10 return age; 11 } 12 ..........
这个util.js的使用也很简单,大致就是
1 var util = require('lib/util'); 2 3 var str = util.convertCase('abc'); 4 var age = util.getAge('1990-01-01');//The world belongs to 90s now;
是不是很简单呢?是的,只要你本身的代码已经做好了模块化,切换到commonjs还是非常容易的.希望我的例子能够足以说明问题,让大伙能毫不犹豫的投入到commonjs的怀抱中;