解析:
1、首先读到第一行发现‘var’,于是存储‘a =undefined’; 2、读到第二行发现‘function’,于是存储‘fn1 = function fn1(a){alert(a);var a =2;}’整个函数块都存储下来; 预解析结束。
1、第一行看到a,于是到仓库去找a,然后看到等号,就是表达式,会到仓库去更改值,由‘a=未定义’更改成‘a=1’; 2、第二行看到function函数,就是声明,不能对值进行修改,仓库中a 的值还是1不变。 3、继续读代码看到fn1(a);函数调用,就是让函数里面的代码开始执行。我们知道函数也是一个域,只要是域就会发生域解析,于是函数里面的代码要先进行预解析,再逐行解读代码。如下:①② ①预解析:函数第一行function fn1(a){看到参数a,是要找的关键字,就相当于放着一个空值在这,即函数体的仓库中存放着a = 未定义; 然后继续预解析,看看有没有var、function等没有。 由此局部预解析结束; ②逐行解读代码:第一行看到function fn1(a){,看到参数,因为函数在调用时传参进来,所以函数在调用时直接读取全局变量中a的值a = 1,即function fn1(var a = 1){;(参数是表达式,可以更改局部仓库中的值,所以函数体内仓库中a 的值由‘a = 未定义’改为‘a = 1’)。继续解读代码,读到alert(a);,然后到局部仓库中去寻找a,发现a的值是1,于是弹出1。继续解读代码,读到a =2;于是到局部仓库中寻找a,因为有等号,所以直接把局部仓库中的值改为‘a = 2’; 4、继续解读代码,看到alert(a);,于是到全局仓库中寻找a,弹出1(因为是到外面的大仓库中寻找,不是局部仓库)。
注意:我们可以在函数内部找函数外面的变量,但是不能在函数外面找函数里面的变量。找不到就会直接报错!
第一步:先定义一个空变量var str = ''; 第二步:把空的变量名放在函数内部,因为在函数解读中局部作用域找不到该变量,会到全局仓库中寻找;(根据作用域链找到父级作用域)然后通过等号,来把函数体内的变量赋值给该变量,这样,函数体内的局部变量值就会到全局变量中; 第三步:在函数体外面访问空变量名str,就会弹出‘鸡腿’;因为此时函数体内的局部变量已经是全局变量了。
注意:函数的大括号才是一个域,if中的大括号不是一个作用域,同理for的大括号也不是一个作用域。作用域的一个标志是先解析后执行。
与
if(){ } var a = 1; alert(a);效果是一样的,if判断是通透,不会先解析后执行。
注意:不要随便在if、for里面定义变量、函数,如果想定义全局变量、全局函数,那么在if、for外面定义。否则存在兼容性问题(火狐不兼容)。如下,不要这么写:
if(true){ var a = 1; function fn1({ alert(123); } }最好定义在外面:
if(true){ } var a = 1; function fn1({ alert(123); }有三个按钮。
var btn = document.getElementsByTagName('input'); for(var i=0;i<btn.length;i++){ btn[i].onclick = function(){ alert(i);//3 } }上面代码可以简化为:
for(var i=0;i<btn.length;i++){ btn[i].onclick = function(){。。。} }因为有for所以会先运行for的内容,运行速度非常快取决于内存的性能,函数体等for运行完之后i的值已经变成3即:i = 3;for循环执行完之后才能发生点击事件,不执行完点不上去,点完之后函数内就会去找i,但函数内部没有i,所以会到父级去找i,此时父级的 i 的值已经是3,所以会弹出3。