作用域与作用域链
一、作用域
1.1、全局作用域
(1)最外层函数和在最外层函数外的变量拥有全局作用域:
1 var i=1; 2 function a(){ 3 var aw="qw"; 4 console.log(aw); 5 function ba(){ 6 var qq="aaa"; 7 } 8 } 9 10 console.log(i); 11 condole.log(aw); 12 a(); 13 14 //1 15 //Uncaght ReferenceError : aw is not defined(...) 16 //qw
(2)所有没有声明变量都自动声明拥有全局作用域:
1 function c(){ 2 o="qw"; 3 4 function ba(){ 5 p="aaa"; 6 } 7 ba(); 8 } 9 c(); 10 11 console.log(o); 12 console.log(p); 13 14 // qw 15 // aaa
o 在函数c()执行完后,拥有全局作用域,可得其值,而函数 ba()在函数执行后p 也被声明为全局变量
(3) 一般情况下,window下所有的属性默认拥有全局作用域,如:window.onload,window.scroll等。
二、局部作用域
与全局作用域相反,局部作用域只作用某些代码段内,只在内部可用
1 function ew(){ 2 var e=2; 3 function q(){ 4 var s=2,w=3; 5 console.log(s); 6 var d=s+w; 7 } 8 q(); 9 console.log(d); 10 } 11 undefined 12 ew(); 13 // 2 14 // Uncaught ReferenceError: d is not defined(…)
二、作用域链
在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。
function fo(){ var a=3; }
这里函数文调用之前,作用域链如图:
fo()
执行此函数时会创建一个称为“运行期上下文”的内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。
这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。新的作用域链如下图所示:
三、代码优化
由作用域链可知,全局变量通常在作用域链最深处,查找时间会更长,所以我们要避免调用全局表量,同时with 语句和try catch 中catch会改变作用域链,应该尽量避免使用with,因为try catch 语句在异常调试非常有用,因此我可以对其进行优化。