本文是google.loader 代码欣赏系列的第二部分。
第一个匪夷所思的地方,可能就是这一段了
if (!google.loader) {基本上就是说,它写了一个这样的语法:
google.loader = {};
google.loader.ServiceBase = "http://www.google.com/uds";
google.loader.ApiKey = "internal";
google.loader.KeyVerified = true;
google.loader.LoadFailure = false;
google.loader.AdditionalParams = "";
(function() {
//大量的函数定义,变量声明以及函数的执行(整整100多行)
})()
}
(function(){})()就算是看得懂,这么绕来绕去,除了炫耀之外,又有意义呢?
匿名函数
先撇开Google的代码,看一下JavaScript其实是支持这种形式的行数定义的:
function(msg){ alert(msg); }("hello world");这其实是两步:第一步,定义了一个函数,相当于:
var abc = function(msg) { alert(msg);}第二步,立刻执行它:
abc("hello world");把两个语句拼接在一起,然后去掉
abc
这个函数的名字,就成了现在的语法形式。
结合前面的
google.loader = {};一起看,其实在这里是定义了google.loader这个对象的一个匿名的成员函数,并且立刻执行了这个成员函数(就是说完成里面的一些列初始化的时候需要干的事情)。
匿名函数的用处
虽然可以理解这里是个匿名函数,但是为什么要这么做呢?
我猜想(请注意,所有这里想的都是一个猜想,并且可能是众多原因之中的一种而已,欢迎大家补充),最主要的考虑是避免命名冲突。
因为这段JavaScript作为Google的其他的各项服务的入口,是会被全球很多的网页引用的。像任何的JavaScript引用(包括PHP的引用),如果被引用的代码和外面的代码一不小心用了同样的名字,就不可避免的发生命名冲突。对于小范围的代码或许还可以用起很怪异的名字的方法企图避免,而对于Google这样的应用,靠运气就有些说不过去。如果是一个匿名函数,外面将永远无法直接访问它(总不能写一个这样的一个没有函数名的调用吧:()
)。从这一点来说,不可能有命名冲突。
封装
另外的一个好处,有可能是为了更好的封装。比如在这个函数里面,有很多的函数定义,比如
q(); p(); m(); g(); i()还有大量的变量:
var j; var h; var l;等等。在JavaScript里面没有简单的
private
这样的定义私有函数或者私有函数的方法。如果调用者可以随心所欲的访问到这些中间的(随时可能变化,甚至移除)成员。对于这么一个开肠破肚,一览无余的对象,从一个API提供者的角度来看(和使用者的角度来看),的确是个挺恐怖的事情。
如果放在一个匿名的函数里面,外界就再也没有办法直接访问到里面的函数了。内部的逻辑被完美的封装了起来。这样一来,这些函数和变量多么的安全!
安全是安全了,但是定义了这么多的函数,仅仅是为了不被外界访问吗?显然不是,所以接下来要做的事情,就是把这些函数输出出去,也就是google_exportSymbol
,或者说是函数g()
要做的事情。
且听下回分解。
注:接下来,或许还要说说: 输出函数供开发者使用, JavaScript中的面向对象, prototype的扩展方式, Undocumented的神秘参数, 编译后的JavaSscript好比汇编语言,和 Symbol表的启发。