词法作用域:变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定,因此词法作用域也叫做静态作用域。 with和eval除外,所以只能说JS的作用域机制非常接近词法作用域(Lexical scope)。
作用域链:词法作用域的实现机制就是作用域链(scopeChain)。作用域链是一套按名称查找(Name Lookup)的机制,首先在当前执行环境的 ActiveObject 中寻找,没找到,则顺着作用域链到父 ActiveObject 中寻找,一直找到全局调用对象(Global Object)
- 变量查找规则是首先在当前执行环境的 ActiveObject 中寻找,没找到,则顺着执行环境中属性 ScopeChain 指向的 ActiveObject 中寻找,一直到 Global Object(window)方法执行完成后,内部变量值不会被重置,至于变量什么时候被销毁,请参考下面一条方法内变量的生存周期取决于方法实例是否存在活动引用,如没有就销毁活动对象
【
在一个方法中,同名的实参,形参和变量之间是引用关系,也就是JS引擎的处理是同名变量和形参都引用同一个内存地址】,
经典案例
- /*全局(window)域下的一段代码*/
- var i=10;
- function a(){
- alert(i);
- vari = 2;
- alert(i);
- };
- a();
疑问:上面的代码又会输出什么呢?(小子,看这回整不死你!哇哈哈,就不给你选项)
答案:在FireBug中的运行结果是 undefined, 2,下面简单说一下具体执行过程
- 第一个alert输出undefined
- 第二个alert输出 2
- 思考:到底怎么回事儿?
根据【JS引擎变量查找规则,首先在当前执行环境的 ActiveObject 中寻找,没找到,则顺着执行环境中属性 ScopeChain 指向的 ActiveObject 中寻找,一直到 Global Object(window)】,所以在案例中,因为在当前的ActiveObject中找到了有变量 i 的定义,只是值为 “undefined”,所以直接输出 “undefined” 了
<pre name="code" class="javascript"> <pre name="code" class="javascript" style="font-weight: bold;"> var name = "Andyfu";<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
function init() {
function displayName() {
alert(name);
};
var name = "Mozila";
displayName();
}
init();//Mosila
var name = "Andyfu";
function init() {
function displayName() {
alert(name);
};
displayName();
var name = "Mozila";
}
init(); //undefined
var name = "Andyfu";
function init() {
function displayName() {
alert(name);
};
displayName();
name = "Mozila";
}
init(); //Andyfu
var name = "Andyfu";
function init() {
function displayName() {
alert(name);
};
name = "Mozila";
displayName();
}
init(); //Mozila
var name = "Andyfu";
function init()
{
(function() {
alert(name);
})();<span style="font-family: Arial, Helvetica, sans-serif;">//自执行函数</span>
var name = "Mozila";
}
init(); //undefined
var name = "Andyfu";
function init() {
(function() {
alert(name);
})();//自执行函数
name = "Mozila";
}
init(); //Andyfu
var a = 10;
function test() {
a = 100;
alert(a);
alert(this.a);
var a;
alert(a);
}
test();//100 10 100
var a = 10;
function test() {
a = 100;
alert(a);
alert(this.a);
//var a;
alert(a);
}
test();//100 100 100
var a = 10;
alert(this.a);
a=50;
function test() {
a = 100;
alert(a);
alert(this.a);
var a;
alert(a);
}
test();//10 100 50 100