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);