js 10-5

/**
 * Module.js: module and namspace utilities
 * 
 * This is a module of module-related utility functions that are
 * compatible with JSAN-type modules.
 * This module defines the namespace Module.
 */

// Make sure we haven't already been loaded 确认没有载入
var Module;
if (Module && (typeof Module != "object" || Module.NAME))
    throw new Error("Namespace 'Module' already exists");

// Create our namespace 创建名字空间
Module = {};           

// This is some metainformation about this namespace 有些元信息在名字空间
Module.NAME = "Module";    // The name of this namespace 名字空间的名字
Module.VERSION = 0.1;      // The version of this namespace 名字空间的版本

// This is the list of public symbols that we export from this namespace.
// These are of interest to programers who use modules
//公开符号的列表,可以从名字空间输出
Module.EXPORT = ["require", "importSymbols"];

// These are other symbols we are willing to export. They are ones normally
// used only by module authors and are not typically imported
//其他我们愿意出口的符号,常常只被模块作者使用,不会出口的。
Module.EXPORT_OK = ["createNamespace", "isDefined",
                    "registerInitializationFunction",
                    "runInitializationFunctions",
                    "modules", "globalNamespace"];


// Now start adding symbols to the namespace 现在开始加入符号到名字空间
Module.globalNamespace = this;  // So we can always refer to the global scope 我们一直引用全局
Module.modules = { "Module": Module };  // Module name->namespace map.

/**
 * This function creates and returns a namespace object for the
 * specified name and does useful error checking to ensure that the
 * name does not conflict with any previously loaded module.  It
 * throws an error if the namespace already exists or if any of the
 * property components of the namespace exist and are not objects.
 *这个函数创建和返回一个名字空间对象为这特殊名字和做有用的错误检查,可以确定名字没有冲突对任何先前
 *载入的模块。它抛出一个错误,如果名字空间已经有或者任何属性元件已经存在并不是对象。
 * Sets a NAME property of the new namespace to its name.
 * If the version argument is specified, set the VERSION property
 * of the namespace.
 * 设置新名字空间的名字属性。如果版本参数指定了,设置版本属性。
 * A mapping for the new namespace is added to the Module.modules object
 *新名字空间的地图加入Module.modules 对象
 */

Module.createNamespace = function(name, version) {
    // Check name for validity.  It must exist, and must not begin or 检查名字的合法性,它必须存在,
    // end with a period or contain two periods in a row.并且不能开始或结束带.,或者包含2个.在一行中。
    if (!name) throw new Error("Module.createNamespace(): name required");
    if (name.charAt(0) == '.' ||
        name.charAt(name.length-1) == '.' ||
        name.indexOf("..") != -1) 
        throw new Error("Module.createNamespace(): illegal name: " + name);

    // Break the name at periods and create the object hierarchy we need
    //用.划分名字并创建对象等级
    var parts = name.split('.');

    // For each namespace component, either create an object or ensure that
    // an object by that name already exists.
    //对每个名字空间元组,每一个创建一个对象,或者确认这个对象名字已经存在。
    var container = Module.globalNamespace;
    for(var i = 0; i < parts.length; i++) {
        var part = parts[i];
        // If there is no property of container with this name, create
        // an empty object.如果名字里没有装入属性,创建一个新对象。
        if (!container[part]) container[part] = {};
        else if (typeof container[part] != "object") {
            // If there is already a property, make sure it is an object
            //如果已经有了属性,确定他是个对象
            var n = parts.slice(0,i).join('.');
            throw new Error(n + " already exists and is not an object");
        }
        container = container[part];
    }
    
    // The last container traversed above is the namespace we need.
    //历容器的名字空间是我们需要的。
    var namespace = container;

    // It is an error to define a namespace twice.  It is okay if our
    // namespace object already exists, but it must not already have a 
    // NAME property defined.
    //这个错误定义个名字空间两次。如果名字空间已经存在也没关系,但他必须不能定义有名字属性。
    if (namespace.NAME) throw new Error("Module "+name+" is already defined");

    // Initialize name and version fields of the namespace 初始化姓名、版本。
    namespace.NAME = name;
    if (version) namespace.VERSION = version;
    
    // Register this namespace in the map of all modules 注册名字空间到 模块地图
    Module.modules[name] = namespace;

    // Return the namespace object to the caller 返回名字空间对象给调用者。
    return namespace;
}


/**
 * Test whether the module with the specified name has been defined.
 *测试是否模块带有已经被定义过的特定名称,如果已经定义返回真,没有返回假。
 * Returns true if it is defined and false otherwise.
 */
Module.isDefined = function(name) {
    return name in Module.modules;
};

/**
 * This function throws an error if the named module is not defined
 * or if it is defined but its version is less than the specified version.
 * If the namespace exists and has a suitable version, this function simply
 * returns without doing anything. Use this function to cause a fatal
 * error if the modules that your code requires are not present.
 *这个函数在如果命名模块没有被定义,或者被定义但版本低于指定的版本时,抛出一个错误。
 *如果名字空间存在并有合适的版本,这个函数简单的不返回任何东西。用这个函数产生一个终极错误,
 *如果你编写的模块的要求没有被实现。
 */
Module.require = function(name, version) {
    if (!(name in Module.modules)) {
        throw new Error("Module " + name + " is not defined");
    }

    // If no version was specified, there is nothing to check 如果没有指定版本,不用检查。
    if (!version) return;

    var n = Module.modules[name];

    // If the defined version is less than the required version or of 
    // the namespace does not declare any version, throw an error.
    //如果定义的版本低于要求的版本或者命名空间没有声明任何版本,抛出一个错误。
    if (!n.VERSION || n.VERSION < version)
    throw new Error("Module " + name + " has version " +
                    n.VERSION + " but version " + version +
                    " or greater is required.");
};


/**
 * This function imports symbols from a specified module.  By default, it
 * imports them into the global namespace, but you may specify a different
 * destination as the second argument.
 * 这个函数从指定模块导入。如果默认,将导入到全局命名空间,但你可以指定一个不同目标到第二参数。
 * If no symbols are explicitly specified, the symbols in the EXPORT
 * array of the module will be imported.  If no such array is defined,
 * and no EXPORT_OK is defined, all symbols from the module will be imported. 
 * 如果没有明确指定符号,在EXPORT模块数组里的符号将被导入。如果没有定义这样的数组,也没有EXPORT_OK
 * 所有模块的符号将被导入。
 * To import an explicitly specified set of symbols, pass their names as
 * arguments after the module and the optional destination namespace. If the
 * modules defines an EXPORT or EXPORT_OK array, symbols will be imported
 * only if they are listed in one of those arrays.
 * 在模块和可选目的地命名空间之后,通过他们的名字作为参数导入指定的一组符号。如果模块定义了EXPORT或者
 * EXPORT_OK数组,仅仅只在他们列在其中之一个数组中的符号会被导入。
 */
Module.importSymbols = function(from) {
    // Make sure that the module is correctly specified.  We expect the
    // 确定模块被正确的指定,我们希望模块的名字对象仅仅用一个字符串。
    // module's namespace object but will try with a string, too
    if (typeof from == "string") from = Module.modules[from];
    if (!from || typeof from != "object")
        throw new Error("Module.importSymbols(): " + 
                        "namespace object required");

    // The source namespace may be  followed by an optional destination
    // namespace and the names of one or more symbols to import;
    // 资源名字空间后面有一个目的地选项,一个或多个符号名被导入
    var to = Module.globalNamespace; // Default destination 缺省目的地
    var symbols = [];                // No symbols by default 缺省符号
    var firstsymbol = 1;             // Index in arguments of first symbol name 第一个符号名参数目录

    // See if a destination namespace is specified 如果目的地被指定了
    if (arguments.length > 1 && typeof arguments[1] == "object") {
        if (arguments[1] != null) to = arguments[1]; 
        firstsymbol = 2;
    }

    // Now get the list of specified symbols 现在列出指定符号列表
    for(var a = firstsymbol; a < arguments.length; a++)
        symbols.push(arguments[a]);
    
    // If we were not passed any symbols to import, import a set defined
    // by the module, or just import all of them.
    // 如果我们没有传递导入任何符号,就导入模块指定的一组或者所有。
    if (symbols.length == 0) {
        // If the module defines an EXPORT array, import
        // the symbols in that array. 如果模块定义EXPORT数组,导入这个数组的所有符号。
        if (from.EXPORT) {
            for(var i = 0; i < from.EXPORT.length; i++) {
                var s = from.EXPORT[i];
                to[s] = from[s];
            }
            return;
        }
        // Otherwise if the modules does not define an EXPORT_OK array,
        // just import everything in the module's namespace
        // 否则如果模块没有定义EXPORT_OK数组,导入模块命名空间的所有
        else if (!from.EXPORT_OK) {
            for(s in from) to[s] = from[s];
            return;
        }
    }

    // If we get here, we have an explicitly specified array of symbols
    // to import. If the namespace defines EXPORT and/or EXPORT_OK arrays,
    // ensure that each symbol is listed before importing it.
    // Throw an error if a requested symbol does not exist or if 
    // it is not allowed to be exported
    // 如果到这里,我们有一个明确指定的符号数组导入。如果名字空间定义了EXPORT或者/和EXPORT_OK数组,
    // 在导入之前,确定每个符号都被列表了。
    // 如果一个需要的符号没有凑在或者不被允许输出,就抛出错误。
    var allowed;
    if (from.EXPORT || from.EXPORT_OK) {
        allowed = {};
        // Copy allowed symbols from arrays to properties of an object.
        // This allows us to test for an allowed symbol more efficiently.
        // 从数组里拷贝出允许的符号 到对象的属性。
        if (from.EXPORT) 
            for(var i = 0; i < from.EXPORT.length; i++)
                allowed[from.EXPORT[i]] = true;
        if (from.EXPORT_OK)
            for(var i = 0; i < from.EXPORT_OK.length; i++)
                allowed[from.EXPORT_OK[i]] = true;
    }
    
    // Import the symbols 导入符号
    for(var i = 0; i < symbols.length; i++) {
        var s = symbols[i];              // The name of the symbol to import 符号名被导入
        if (!(s in from))                // Make sure it exists 确认存在
            throw new Error("Module.importSymbols(): symbol " + s +
                            " is not defined");
        if (allowed && !(s in allowed))  // Make sure it is a public symbol 确认公共符号
            throw new Error("Module.importSymbols(): symbol " + s +
                            " is not public and cannot be imported.");
        to[s] = from[s];                 // Import it 导入
    }
};


// Modules use this function to register one or more initialization functions
// 模块用函数来注册一个或者多个初始化函数
Module.registerInitializationFunction = function(f) {
    // Store the function in the array of initialization functions 储存函数到初始化函数组中
   Module._initfuncs.push(f);
    // If we have not yet registered an onload event handler, do so now. 如果没有注册载入事件句柄,
    //现在载入。
    Module._registerEventHandler();
}

// A function to invoke all registered initialization functions.
// In client-side JavaScript, this will automatically be called in
// when the document finished loading.  In other contexts, you must
// call it explicitly.
// 一个函数被所有初始注册函数调用。在客户端js,这个可以自动被调用,当文档载入完毕。
// 在另外一些情况,我们必须明确调用。
Module.runInitializationFunctions = function() {
    // Run each initialization function, catching and ignoring exceptions
    // so that a failure by one module does not prevent other modules
    // from being initialized.
    // 运行每个初始化函数,抓住或者忽略意外,因此一个模块的失败不能阻止其他模块初始化
    for(var i = 0; i < Module._initfuncs.length; i++) {
        try { Module._initfuncs[i](); }
        catch(e) { /* ignore exceptions */}
    }
    // Erase the array so the functions are never called more than once. 
    // 擦除数组,所以函数不会再被调用一次。
    Module._initfuncs.length = 0;
}

// A private array holding initialization functions to invoke later 
// 有数组保持始化函数以后被调用
Module._initfuncs = [];

// If we are loaded into a web browser, this private function registers an 
// onload event handler to run the initialization functions for all loaded 
// modules. It does not allow itself to be called more than once.
// 如果我们载入一个web浏览器,私有化函数注册一个载入句柄来运行初始化函数,为了所有载入模块,
// 它不云溪自己再调用多过于一次。
Module._registerEventHandler = function() {
    var clientside =   // Check for well-known client-side properties 检查客户端属性
        "window" in Module.globalNamespace &&
        "navigator" in window;

    if (clientside) {
        if (window.addEventListener) {  // W3C DOM standard event registration
            window.addEventListener("load", Module.runInitializationFunctions, 
                                    false);
        }
        else if (window.attachEvent) {  // IE5+ event registration
            window.attachEvent("onload", Module.runInitializationFunctions);
        }
        else {
            // IE4 and old browsers
            // If the <body> defines an onload tag, this event listener
            // will be overwritten and never get called.
            window.onload = Module.runInitializationFunctions;
        }
    }

    // The function overwrites itself with an empty function so it never
    // gets called more than once.
    Module._registerEventHandler = function() {};
}
posted on 2012-08-07 16:15  rorodo  阅读(368)  评论(0)    收藏  举报