PhoneGap 1.5版本 cordova.js 简析 1
PhoneGap升级到1.5除了内部的名字变动外,更改最多的是js部分的调用机制.套用官方论坛的描述就是: 我们希望任意API对于开发者是可安装、可发现、可卸载的,同时希望改变各种平台的js实现存在差异的现状。最大的变化就是在js中引入了模块化机制。
PS: 下文中使用的代码为phonegap 1.5 - android的js代码,作为学习对部分原理简单的介绍一下
所谓的模块化机制其实就是所有的功能定义和调用都必须通过全局定义的require和define两个函数来实现。这种方式既避免了变量名称和作用域的污染,也简化了注册和使用方式等等(废话就不说了)。具体的定义和调用代码格式如下:
//定义
define('cordova/channel', function(require, exports, module) {
//..............
});
//调用
var channel = require('cordova/channel');
我们就单纯的对这两个函数进行下分析,通过上述代码可以看到 define包含两个参数:一个标识这个功能的path:'cordova/channel';一个匿名函数:function(require, exports, module).而require就通过define中的path来直接去的对象功能.那么让我们先看下两个函数的定义:
require = function(id) {
if (!modules[id]) {
throw "module " + id + " not found";
}
return modules[id].factory ? build(modules[id]) : modules[id].exports;
}
define = function(id, factory) {
if (modules[id]) {
throw "module " + id + " already defined";
}
modules[id] = {
id : id,
factory : factory
};
}
可以看到modules在其中非常重要,应该是一个缓存对象的感觉.define函数只是简单的将对象放入到modules里面,而require也很简单,如果modules中不存在直接报错,否则如果存在工厂方法就返回build函数的结果否则返回exports对象.所以可以了解到关键点应该在build和modules.
var modules = {};
function build(module) {
var factory = module.factory;
module.exports = {};
delete module.factory;
factory(require, module.exports, module);
return module.exports;
}
通过上述代码(源码274行)可以看到modules是一个包含在匿名函数中的对象,用来保存其他的注册对象,build就是将没有通过factory创建的对象实例化,然后再放入module内部.所以回到define函数我们可以看到的定义都是如下结构:
define('cordova/plugin/myPlugin', function(require, exports, module) {
var myObject = {};
//......
module.exports = myObject ;
});
实际是过程是将一个生成后的对象实例或者方法通过module.exports暴露给前面的的modules['cordova/plugin/myPlugin'],而在下次需要使用的时候,将会直接通过require函数从modules['cordova/plugin/myPlugin'].exports 取得.这里还有一个地方就是三个参数require, exports, module,实际上 exports和module.exports是一个东西,代码如下,
factory(require, module.exports, module);
参考了多个phonegap提供的功能定义,发现exports也并没有被使用,所以每次看的时候不需要被这个东西和module的关系把自己搞晕.但是由于js参数传递的特点不能用
exports = myObject进行替换(具体原因可以自己试试看再查资料,这里不做讨论)