一、作用域
(一)、在JavaScript里的全局环境就是一个对象,这个对象就是JavaScript运行环境的根;对于浏览器中的JavaScript来说,这个根对象就是window对象(非浏览器宿主程序中可能不叫window),对于全局的JavaScript语句来说,window对象就相当于当前作用域。
案例:
var yourName = "yuyu";myName ="bobo"; alert(myName +"like"+yourName); ChangeNames(); //调用改名函数 function ChangeNames() { alert("Your old name is " + yourName); //输出:Your old name is undefined alert("My old name is" + myName); //my old name is bobo var yourName = "王金凤"; myName = "liswen"; alert(myName + " like" + yourName); //liswen like王金凤 }; alert(myName + " like" + yourName); //liswen likeyuyu
注:1、用“var”修饰的yourName标识符在函数内外是两个东西;外面的“yuyu”不会因为ChangeNames函数内改变成“王金凤"而改变,回到外面还是”yuyu".而myName没有用“var”修饰,就是一个东西了,函数内的修改也就在函数外表现出来了。
2、函数中yourName出现undefined的原因是当代码进入一个函数时,Js会创建一个新的作用域,来作为当前作用域的自作用域,然后,将当前全局作用域切换为这个新建的子作用域,开始执行函数逻辑,js执行引擎会把此函数内的逻辑代码,当作一个代码单元来分析和执行。在第一步的预编译分析中,js执行引擎将所有定义式函数直接创建为作用域上的函数变量,并将其值初始化为定义的函数代码逻辑,也就是为其建立了可调用的函数变量。而对于所有“var”定义的变量,也会在第一步编译中创建起来,并将初始值设为undefined;js执行代码,遇到对函数名或者变量名使用时,js执行引擎首先在当前作用域查找函数或变量,如果没有就到上层作用域查找,。因此,前面的语句引用后面语句定义的“var"变量时,该变量其实已经存在,只是初始值为undefined。
3、用“var”定义的变量只对本作用域有效,尽管此时上层作用域有同名的东西,都与本作用域的“var"作用域无关,退出本作用域后,此”var"消失,回到原来的作用域该有啥有啥。
4、js在查找标识符的时候,除非指明特定对象,否则会沿着作用域链寻找符合这一标识符的变量或者属性,甚至会自动创建该标识符,正是由于js这种灵活性,我们就可能在不经意间覆盖率原来的变量和属性,或者无意中创建了大量无用的全局属性,甚至在毫不知情的情况下影响了其他代码的逻辑,从而造成许多很难排除的bug。
(二)js提供的调用上下文信息有几个:一个是函数本身,一个是函数的caller属性,另外还有this关键字和arguments隐含对象。
当代码运行在函数体内的作用域时空时,函数本身的标识符是可以用的。比如下面的代码就可以输出函数自身的定义:
function aFunc() { alert(aFunc.toString()); //函数体内可以使用自身的标识符 }; aFunc(); //调用函数输出结果:
function aFunc() {
alert(aFunc.toString()); //函数体内可以使用自身的标识符
}
函数自身有一个caller属性,其表示调用当前函数的上层函数。这就提供了一个可以追溯函数调用来源的线索,特别对于调试JavavScript特别重要。
function WhoCallMe(){ alert("My caller is " + WhoCallMe.caller); //输出自己的caller }; function CallerA(){ WhoCallMe(); }; function CallerB(){ WhoCallMe(); }; alert(WhoCallMe.caller); //输出:null WhoCallMe(); //输出:my caller is null CallerA(); //输出:my caller is function CallerA(){WhoCallMe();} CallerB(); //输出:my caller is function CallerB(){WhoCallMe();}
如果函数的caller属性1是Null,表示函数没有被调用或者是被全局代码调用,函数的caller属性值实际上是动态变化的,函数的初始caller值都为null,当调用一个函数时,如果代码已经运行在某个函数体内,js执行引擎会将被函数的caller属性设置为当前函数。在退出被调用函数作用域时,被调函数的caller属性又会恢复为null值。