Dojo源码分析(二)

前端之家收集整理的这篇文章主要介绍了Dojo源码分析(二)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

经过上一篇分析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

猜你在找的Dojo相关文章