flipsnap.js
该库在代码中的使用示例如下:
//函数的引用
var flipsnap = Flipsnap("#wrap");
下面是flipsnap.js的实现。下面是抽取了其基本框架。
(function(window, document, undefined) {
var ...; /* 局部变量 */
function(){} ; /* 内部函数 */
function Flipsnap(){}; /* Flipsnap()函数定义,该函数为内部函数 */
Flipsnap.prototype.init = function(){}; /* 定义Flipsnap()函数的原型链 */
Flipsnap.prototype.handleEvent = function(){}; /* 定义Flipsnap()函数的原型链 */
......
window.Flipsnap = Flipsnap; /* 将定义的内部函数Flipsnap()赋值到window对象下,成为全局函数 */
})(window, window.document); /* 执行该无名函数,使函数内的操作都实现 */
通过上面的代码,可以看到flipsnap.js就是生成了一个window的对象,该对象是一个函数Flipsnap()。如果这是一个普通的函数(什么是?),那么在使用的时候可能有两种情况,一是直接调用该函数执行一些操作,返回的结果是true或者false;二是使用new实例化该函数,返回的结果为该函数的一个实例。我们看应用的示例,好像都不符合上面说的两种情况。其实,原因就在于Flipsnap()函数实现的一些特点。
function Flipsnap(element, opts) {
return (this instanceof Flipsnap)
? this.init(element, opts)
: new Flipsnap(element, opts);
}
Flipsnap.prototype.init = function(element, opts) {
var self = this;
/* ... */
return self;
};
可以看到,Flipsnap()函数返回的已经是一个其本身的实例。
cordova-2.0.0.js
该js库主要学习其模块化机制。
下面以Android的cordova-2.0.0.js为例分析其实现结构。
;(function() {
// file: lib/scripts/require.js
var require,
define;
(function () {
var modules = {};
//初始化模块
function build(module) {
var factory = module.factory;
module.exports = {};
delete module.factory; //模块的factory属性被删除
factory(require, module.exports, module); //初始化模块
return module.exports; //模块添加了exports属性,exprots属性在factory属性中实现
}
//获取模块的执行部分exports属性(对外表现为初始化一个模块),前提是模块已经初始化,exports属性在factory属性中实现,但是未初始化
require = function (id) {
if (!modules[id]) {
throw "module " + id + " not found";
}
//判断该模块是否已经初始化的依据是factory属性是否还存在
return modules[id].factory ? build(modules[id]) : modules[id].exports;
};
//define()函数注册模块,modules对象存放
define = function (id, factory) {
if (modules[id]) {
throw "module " + id + " already defined";
}
//注册时,每个模块都由modules的一个成员对象保存,只有id和factory两个属性
modules[id] = {
id: id,
factory: factory
};
};
define.remove = function (id) {
delete modules[id];
};
})(); // 立即执行
//Export for use in node
if (typeof module === "object" && typeof require === "function") {
module.exports.require = require;
module.exports.define = define;
}
define("cordova",function(){}); /* 调用define()函数,注册模块 */
......
window.cordova = require('cordova'); /* 初始化cordova模块,这是第一个被初始化的模块 */
(function (context) {})(window); //立即执行,后面有详细讲解
})(); // 立即执行
下面是注册模块部分实现的示例,以FileSystem模块为例。
// file: lib/common/plugin/FileSystem.js
define("cordova/plugin/FileSystem", function(require, exports, module) {
var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
/**
* An interface representing a file system
*
* @constructor
* {DOMString} name the unique name of the file system (readonly)
* {DirectoryEntry} root directory of the file system (readonly)
*/
var FileSystem = function(name, root) {
this.name = name || null;
if (root) {
this.root = new DirectoryEntry(root.name, root.fullPath);
}
};
module.exports = FileSystem;
});
上面这种先注册,后根据需要初始化的实现,很好的解决了模块之间的依赖关系。例如a需要依赖b模块,那么在a模块初始化的时候,就需要先初始化b模块(如果b模块没有初始化的话),或者直接获得b模块的exports(b模块已经初始化了)。例如上面的var DirectoryEntry = require('cordova/plugin/DirectoryEntry');一句。
下面看看(function (context) {})(window);的实现。
// file: lib/scripts/bootstrap.js
(function (context) {
var channel = require("cordova/channel"),
_self = {
boot: function () {
/**
* Create all cordova objects once page has fully loaded and native side is ready.
*/
channel.join(function() {
var builder = require('cordova/builder'),
base = require('cordova/common'),
platform = require('cordova/platform');
// Drop the common globals into the window object, but be nice and don't overwrite anything.
builder.build(base.objects).intoButDontClobber(window);
// Drop the platform-specific globals into the window object
// and clobber any existing object.
builder.build(platform.objects).intoAndClobber(window);
// Merge the platform-specific overrides/enhancements into
// the window object.
if (typeof platform.merges !== 'undefined') {
builder.build(platform.merges).intoAndMerge(window);
}
// Call the platform-specific initialization
platform.initialize();
// Fire event to notify that all objects are created
channel.onCordovaReady.fire();
// Fire onDeviceReady event once all constructors have run and
// cordova info has been received from native side.
channel.join(function() {
require('cordova').fireDocumentEvent('deviceready');
}, channel.deviceReadyChannelsArray);
}, [ channel.onDOMContentLoaded, channel.onNativeReady ]);
}
};
// boot up once native side is ready
channel.onNativeReady.subscribeOnce(_self.boot);
// _nativeReady is global variable that the native side can set
// to signify that the native code is ready. It is a global since
// it may be called before any cordova JS is ready.
if (window._nativeReady) {
channel.onNativeReady.fire();
}
}(window));
iscroll.js
下面是iscroll.js的实现。下面是抽取了其基本框架。
(function(){
var ...; //全局变量初始化
// Constructor
iScroll = function (el, options) {
......
};
// Prototype
iScroll.prototype = {
//原型链变量的初始化
enabled: true,
x: 0,
......
//原型链函数的实现
handleEvent: function (e) {},
_checkDOMChanges: function () {},
......
};
if (typeof exports !== 'undefined') exports.iScroll = iScroll;
else window.iScroll = iScroll;
})(); //立即执行
将iscroll.js和flipsnap.js比较,可以发现它们的结构基本上都是一样的。不同之处,iscroll函数就是前面说的普通函数,使用的时候,要使用new操作实例化。
toast.js
这是一个jquery的插件,所以其符合jquery插件的格式。
(function($) {
toasting = false; //Global to check if toast is being displayed
toastQue = []; //Array to store messages if a message is already being displayed
//return new toastmessage object
$.toast = function (options) {
return new toastmessage(options);
};
var toastmessage = function(options){
...... //功能实现
};
})(jQuery);