经过上一篇分析dojo.js以后,我们知道,dojo.js主要的任务是探测宿主系统(一般都是浏览器)和动态加载一些js文件。被加载的js文件包含bootstrap.js、loader.js、hostenv_browser.js和_base.js。dojo.js只负责加载这几个文件,dojo的其他模块的js文件加载是由loader.js和hostenv_browser.js来实现的,就是大家很熟悉的dojo.require方法。这一篇主要来分析bootstrap.js,dojo的引导模块。
// bootstrap.js是dojo的引导模块,它主要是负责实例一个全局的dojo变量,还附加实现了一些基础的方法。 (function(){ // 探测Firebug是否存在,Firebug是火狐浏览器的一款经典的Web开发插件。 // 你可以到Firebug的官网,http://getfirebug.com/,去了解Firebug的相关信息。 if(typeof this["loadFirebugConsole"] == "function"){ // 如果你使用Firefox浏览器,并且安装且启用Firebug的控制台功能,那么就会走进来。默认Firebug是不启用控制台功能的。 this["loadFirebugConsole"](); }else{ // 如果你使用其他的浏览器,那么dojo会模拟一个Firebug的控制台。 // 现在主流的浏览器都内置console对象,并且带一个log方法。模拟实现主要是通过console.log()来实现的。 this.console = this.console || {}; // cn数组中包含了console可以调用的方法,其中log一定要放到数组最后面。 var cn = [ "assert","count","debug","dir","dirxml","error","group","groupEnd","info","profile","profileEnd","time","timeEnd","trace","warn","log" ]; // 循环cn数组,并赋值给tn变量。 var i=0,tn; while((tn=cn[i++])){ // 判断console对象有没有tn方法,例如console["assert"] if(!console[tn]){ // 没有的话就走进来,下面是一个匿名函数,这样可以实现局部变量。 (function(){ // 在javascript中,像下面那样写就是把tn变成字符串形式,然后赋给tcn。 var tcn = tn+""; // 这是一个三元运算符,如果console对象中有log方法, // 则把第一个匿名函数赋给console[tcn],否则把第二个空的匿名函数赋给它。 console[tcn] = ('log' in console) ? function(){ // 把arguments函数参数,转成数组对象a,arguments是类数组对象,有长度,可以索引。 // 但是是只读的,不能操作,所以这里要转一下。 var a = Array.apply({},arguments); // 在数组第一个元素前加一个标识,例如assert: a.unshift(tcn+":"); // 用log方法输出结果。 console["log"](a.join(" ")); } : function(){} // fake是欺骗的意思,这里就表示console[tcn]是模拟出来的。 console[tcn]._fake = true; })(); } } } // 定义全局对象dojo。 // 在匿名函数中,你这样写:var dojo;就是定义一个局部变量。 // 但是直接写dojo = {};就会把这个变量注册到window对象上去,形成全局的对象。 if(typeof dojo == "undefined"){ dojo = { // 下面定义的是dojo的属性,属性名前面带下划线的一般表示私有的,是给dojo内部使用的。 _scopeName: "dojo",_scopePrefix: "",_scopePrefixArgs: "",_scopeSuffix: "",_scopeMap: {},_scopeMapRev: {} }; } // 把全局变量dojo,赋给局部变量d。 var d = dojo; // 下面也定义了dijit和dojox两个全局变量。 if(typeof dijit == "undefined"){ dijit = {_scopeName: "dijit"}; } if(typeof dojox == "undefined"){ dojox = {_scopeName: "dojox"}; } if(!d._scopeArgs){ d._scopeArgs = [dojo,dijit,dojox]; } // dojo.global是window对象的一个引用,功能类似windows的快捷方式吧。 d.global = this; // djConfig中的值会赋给dojo.config,下面相当于赋一些默认值给dojo.config。 d.config = { isDebug: false,debugAtAllCosts: false }; if(typeof djConfig != "undefined"){ for(var opt in djConfig){ d.config[opt] = djConfig[opt]; } } // 本地化 dojo.locale = d.config.locale; var rev = "$Rev: 22487 {1}quot;.match(//d+/); // dojo的版本信息 dojo.version = { major: 1,minor: 5,patch: 0,flag: "",// +rev[0],+代表取正数,注意不是++。 revision: rev ? +rev[0] : NaN,toString: function(){ with(d.version){ return major + "." + minor + "." + patch + flag + " (" + revision + ")"; } } } // OpenAjax不知道是什么库 if(typeof OpenAjax != "undefined"){ OpenAjax.hub.registerLibrary(dojo._scopeName,"http://dojotoolkit.org",d.version.toString()); } // 下面这段代码主要是因为IE的toString Bug引起的。大家可以上网搜一下。 // 在for循环对象的属性时,IE是看不见toString和valueOf方法的,其他的浏览器都可以。 // 所以在拷贝对象时,如果是IE浏览器,要额外的拷贝extraNames数组中的属性或方法。 var extraNames,extraLen,empty = {}; // 下面这句话,主要是用来识别IE浏览器的。如果是IE浏览器,extraNames是null,如果是其他浏览器则为空数组。 for(var i in {toString: 1}){ extraNames = []; break; } //下面直接上结果,很容易就明白了。 // IE:dojo._extraNames = ["hasOwnProperty","valueOf","isPrototypeOf",// "propertyIsEnumerable","toLocaleString","toString","constructor"] // Other:dojo._extraNames = [] dojo._extraNames = extraNames = extraNames || ["hasOwnProperty","propertyIsEnumerable","constructor"]; extraLen = extraNames.length; // 这个函数是私有的,用来拷贝对象的属性。 dojo._mixin = function(/*Object*/ target,/*Object*/ source){ // name是属性名,s是属性值 var name,s,i; for(name in source){ // 属性对拷 s = source[name]; if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){ target[name] = s; } } // 下面的代码完全针对IE的toString Bug if(extraLen && source){ for(i = 0; i < extraLen; ++i){ name = extraNames[i]; s = source[name]; if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){ target[name] = s; } } } return target; // Object } // 这个是共有的,大家可以使用,把多个对象的属性值拷贝到第一个参数obj上去。 // 属性相同的时候,最后一个对象的属性值为准。 dojo.mixin = function(/*Object*/obj,/*Object...*/props){ if(!obj){ obj = {}; } for(var i=1,l=arguments.length; i<l; i++){ d._mixin(obj,arguments[i]); } return obj; // Object } // 这个函数私有的,主要是给setObject服务的。 // parts=["parent","child","prop"],是属性名 // create=true,属性不存在时,是否创建空对象 // context对象的上下文,没有的话,就是window对象,全局的。 dojo._getProp = function(/*Array*/parts,/*Boolean*/create,/*Object*/context){ // context没写的话,obj就是window对象 var obj=context || d.global; // 循环parts数组,给obj赋值。 // 如果obj没有该属性,且create为false,则返回obj。否则创建一个空对象,继续递归。 for(var i=0,p; obj && (p=parts[i]); i++){ if(i == 0 && d._scopeMap[p]){ p = d._scopeMap[p]; } obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined)); } return obj; // mixed } // 这个函数可以给对象的子对象的属性赋值,如果子对象不存在,则创建一个。很牛,类似于mkdir -p命令,连子目录一起递归创建。 // 例如:dojo.setObject("parent.child.prop","some value",obj); // 则obj.parent.child.prop的值就是"some value",obj可能没有parent,没有child,更没有prop,没关系此方法会自动创建一个空对象出来。 dojo.setObject = function(/*String*/name,/*Object*/value,/*Object?*/context){ // parts = ["parent","prop"],p = "prop",obj = obj.parent.child.prop var parts=name.split("."),p=parts.pop(),obj=d._getProp(parts,true,context); return obj && p ? (obj[p]=value) : undefined; // Object } // 和_getProp方法一样 dojo.getObject = function(/*String*/name,/*Boolean?*/create,/*Object?*/context){ return d._getProp(name.split("."),create,context); // Object } // 不自动创建属性时,就变成检测该属性存不存在了。 dojo.exists = function(/*String*/name,/*Object?*/obj){ // 前面加两个!!,是javascript转换成boolean型的惯用法。 return !!d.getObject(name,false,obj); // Boolean } // eval是执行javascript代码片段的函数,主要是为了兼容才这么写。 dojo["eval"] = function(/*String*/ scriptFragment){ return d.global.eval ? d.global.eval(scriptFragment) : eval(scriptFragment); // Object } // 原注释的意思是该函数的实现在dojo._firebug.firebug,这里只是占位声明。 //Real functions declared in dojo._firebug.firebug. d.deprecated = d.experimental = function(){}; })();原文链接:https://www.f2er.com/dojo/291740.html