相关知识点:《单页Web应用》28页,高程111页以及underscore源码
高程111页讲过函数声明和函数表达式的唯一区别:解析器会率先读取函数声明,并使其在执行任何代码前可用;至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。看下面两个例子:
alert(sum(10,10)); //20 function sum(num1, num2){ return num1 + num2; }
alert(sum(10,10)); //causes an error var sum = function(num1, num2){ return num1 + num2; };
然后我在看underscore源码的时候遇到了困惑的地方,提炼后的源码如下:
(function() { var root = this; var _ = function(obj) { return new wrapper(obj); }; root['_'] = _; ..... var wrapper = function(obj) { this._wrapped = obj; }; }).call(this);
困惑点:函数_先定义的,函数wrapper后定义的,那函数_执行的时候,岂不是在返回wrapper实例时,因为无法获得wrapper函数内容报错了。困惑了我好长时间。
现在疑惑解决了,其实本身不是应该困惑的东西。咱们假设是按照常规的<script>方式引入underscore.js脚步,我们自己写的js代码肯定是放在了underscore.js的后面,所以当浏览器读到我们自己写的代码的时候,underscore的所有代码已经执行了一遍。执行的具体细节,见下面。
单页Web应用也有相关的知识点:JS引擎在进入作用域时,会对代码分两轮处理。第一轮,初始化变量;第二轮,执行代码。在第一轮,JS引擎分析代码,并做了以下3件事情:
(1)声明并初始化函数参数。
(2)声明局部变量,包括将匿名函数赋值给一个局部变量(注:即函数表达式,此时是undefined),但并不初始化它们。
(3)声明并初始化函数((注:确切的说是函数声明函数)。
对于第二轮,该书只是说执行代码,我认为不只是执行代码,第二轮还包括初始化第一轮未初始化的局部变量和函数表达式。
可以这么理解,在浏览器读到咱们自己写的代码的之前,underscore的所有代码已经执行了一遍,函数wrapper在执行第二轮中已经完成了初始化,所以当浏览器读到咱们自己写的调用函数_时,函数_已经可以引用wrapper函数了。
等等,函数_怎么能引用wrapper函数呢,在underscore.js的立即执行函数完成后,局部变量wrapper已经被垃圾回收机制给回收了,怎么还能被_应用呢。嗯,闭包机制嘛。真正使我困惑是:浏览器怎么知道在初始化_的时候,_内部引用了一个外部函数,根据我以前的理解,初始化函数时,浏览器不会执行函数内部的内容,既然不执行,怎么知道内部有个函数。现在自己猜测在初始化函数的时候,浏览器已经读取了函数内部的内容,并对内容里的变量进行了一次作用域链搜索,不过这个时候搜索到的wrapper应该是undefined吧,因为wrapper的初始化在_初始化的后面,直到调用_的时候,wrapper才真正完全被_引用了。目前先如此理解吧。还要抓紧时间看单页的知识。