容易被忽略的JS腳本特性
更新時間:2011年09月13日 22:02:55 作者:
容易被忽略的JS腳本特性,學(xué)習(xí)js的朋友可以參考下。
一、容易被忽略的局部變量
var a = 5;
(function(){
alert(a);
var a = a ++;
alert(a);
})()
alert(a);
思考這段代碼的執(zhí)行結(jié)果。
執(zhí)行后,看看是否和你想象的一致?
ok,這段代碼里核心的知識點是 var a = a++,其中兩個變量 a 都是匿名函數(shù)內(nèi)部的局部變量,是同一個,和全局變量 a 是不一樣的。
為什么?我們來看看ECMA規(guī)范對變量聲明語句的定義:
Description
If the variable statement occurs inside a FunctionDeclaration, the
variables are defined with function-local scope in that function, as
described in s10.1.3. Otherwise, they are defined with global scope
(that is, they are created as members of the global object, as described
in 10.1.3) using property attributes { DontDelete }. Variables are
created when the execution scope is entered. A Block does not define a new
execution scope. Only Program and FunctionDeclaration produce a new
scope. Variables are initialised to undefined when created. A variable with
an Initialiser is assigned the value of its AssignmentExpression when the
VariableStatement is executed, not when the variable is created.
聲明中提到:進入作用域環(huán)境后,變量就會被創(chuàng)建,并賦予初始值undefined。在變量聲明語句執(zhí)行時才會把賦值表達式的值指派給該變量,而并不是在該變量被創(chuàng)建時。
因此上面的代碼可以等價于:
var a;
a = 5;
(function(){
var a;
alert(a);
a = a ++;
alert(a);
})()
alert(a);
這樣應(yīng)該會更容易理解了。
二、容易被忽略的全局變量
(function(){
var a = b = 5;
})()
alert(b);
這是玉伯幾天前分享到的知識點,蠻有意義的,在此也做個分析。
首先,考慮執(zhí)行結(jié)果為什么是:5。
ok,原因出在 var a = b = 5 這句。
為深入分析這個語句,我們繼續(xù)要參照ECMA規(guī)范對聲明語句的定義:
var a = b = 5;等同為 var a; a = b = 5;兩條語句,后者是賦值表達式,其在ECMA中的定義是這樣的:
Simple Assignment ( = )
The production AssignmentExpression : LeftHandSideExpression =
AssignmentExpression is evaluated as follows:
1. Evaluate LeftHandSideExpression.
2. Evaluate AssignmentExpression.
3. Call GetValue(Result(2)).
4. Call PutValue(Result(1), Result(3)).
5. Return Result(3).
對于a = b = 5;先執(zhí)行左邊表達式 a,這是一個標(biāo)識符表達式,根據(jù)規(guī)范第 10.1.4,其執(zhí)行方式如下:
During execution, the syntactic production PrimaryExpression : Identifier
is evaluated using the following algorithm:
1. Get the next object in the scope chain. If there isn't one, go to step 5.
2. Call the [[HasProperty]] method of Result(1), passing the Identifier as
the property.
3. If Result(2) is true, return a value of type Reference whose base
object is Result(1) and whose property name is the Identifier.
4. Go to step 1.
5. Return a value of type Reference whose base object is null and whose
property name is the Identifier.
搜尋作用域鏈,找到最近的一個 a 的引用,很明顯,在匿名函數(shù)內(nèi)部作用域就可以找到,于是變量 a 確定下來。
接著再執(zhí)行右邊的表達式 b = 5 ,還是一個賦值表達式,重復(fù)賦值規(guī)則第一步,因為變量 b 在匿名函數(shù)環(huán)境內(nèi)未聲明過,所以接著去 window 全局環(huán)境下去找 window.b ,被隱式聲明為全局變量,最后賦值為 5,根據(jù)規(guī)則第五步,表達式的結(jié)果也會再賦值給 a。最終達到 a 和 b 都為 5 ,區(qū)別是 a 是局部變量,而 b 是全局變量。
我們再來理一下 (function(){var a = b = 5})() 表達式內(nèi)部整體的執(zhí)行順序:
1.匿名函數(shù)內(nèi)創(chuàng)建變量a;
2.賦予初始值undefined;
3.取得變量a的引用; //a
4.取得變量b的引用; //window.b
5.對數(shù)字5求值;
6.賦值5給b的引用:window.b;
7.返回b = 5的結(jié)果5給a的引用:a;
8.返回a = 5的結(jié)果5;
很明顯,中間的一個步驟使得變量 b 被聲明為全局變量,明白之后,我們不難找到代碼的優(yōu)化點:只需將變量 b 顯式聲明為局部變量:
(function(){
var a,b;
a = b = 5;
})()
復(fù)制代碼 代碼如下:
var a = 5;
(function(){
alert(a);
var a = a ++;
alert(a);
})()
alert(a);
思考這段代碼的執(zhí)行結(jié)果。
執(zhí)行后,看看是否和你想象的一致?
ok,這段代碼里核心的知識點是 var a = a++,其中兩個變量 a 都是匿名函數(shù)內(nèi)部的局部變量,是同一個,和全局變量 a 是不一樣的。
為什么?我們來看看ECMA規(guī)范對變量聲明語句的定義:
復(fù)制代碼 代碼如下:
Description
If the variable statement occurs inside a FunctionDeclaration, the
variables are defined with function-local scope in that function, as
described in s10.1.3. Otherwise, they are defined with global scope
(that is, they are created as members of the global object, as described
in 10.1.3) using property attributes { DontDelete }. Variables are
created when the execution scope is entered. A Block does not define a new
execution scope. Only Program and FunctionDeclaration produce a new
scope. Variables are initialised to undefined when created. A variable with
an Initialiser is assigned the value of its AssignmentExpression when the
VariableStatement is executed, not when the variable is created.
聲明中提到:進入作用域環(huán)境后,變量就會被創(chuàng)建,并賦予初始值undefined。在變量聲明語句執(zhí)行時才會把賦值表達式的值指派給該變量,而并不是在該變量被創(chuàng)建時。
因此上面的代碼可以等價于:
復(fù)制代碼 代碼如下:
var a;
a = 5;
(function(){
var a;
alert(a);
a = a ++;
alert(a);
})()
alert(a);
這樣應(yīng)該會更容易理解了。
二、容易被忽略的全局變量
復(fù)制代碼 代碼如下:
(function(){
var a = b = 5;
})()
alert(b);
這是玉伯幾天前分享到的知識點,蠻有意義的,在此也做個分析。
首先,考慮執(zhí)行結(jié)果為什么是:5。
ok,原因出在 var a = b = 5 這句。
為深入分析這個語句,我們繼續(xù)要參照ECMA規(guī)范對聲明語句的定義:
var a = b = 5;等同為 var a; a = b = 5;兩條語句,后者是賦值表達式,其在ECMA中的定義是這樣的:
復(fù)制代碼 代碼如下:
Simple Assignment ( = )
The production AssignmentExpression : LeftHandSideExpression =
AssignmentExpression is evaluated as follows:
1. Evaluate LeftHandSideExpression.
2. Evaluate AssignmentExpression.
3. Call GetValue(Result(2)).
4. Call PutValue(Result(1), Result(3)).
5. Return Result(3).
對于a = b = 5;先執(zhí)行左邊表達式 a,這是一個標(biāo)識符表達式,根據(jù)規(guī)范第 10.1.4,其執(zhí)行方式如下:
復(fù)制代碼 代碼如下:
During execution, the syntactic production PrimaryExpression : Identifier
is evaluated using the following algorithm:
1. Get the next object in the scope chain. If there isn't one, go to step 5.
2. Call the [[HasProperty]] method of Result(1), passing the Identifier as
the property.
3. If Result(2) is true, return a value of type Reference whose base
object is Result(1) and whose property name is the Identifier.
4. Go to step 1.
5. Return a value of type Reference whose base object is null and whose
property name is the Identifier.
搜尋作用域鏈,找到最近的一個 a 的引用,很明顯,在匿名函數(shù)內(nèi)部作用域就可以找到,于是變量 a 確定下來。
接著再執(zhí)行右邊的表達式 b = 5 ,還是一個賦值表達式,重復(fù)賦值規(guī)則第一步,因為變量 b 在匿名函數(shù)環(huán)境內(nèi)未聲明過,所以接著去 window 全局環(huán)境下去找 window.b ,被隱式聲明為全局變量,最后賦值為 5,根據(jù)規(guī)則第五步,表達式的結(jié)果也會再賦值給 a。最終達到 a 和 b 都為 5 ,區(qū)別是 a 是局部變量,而 b 是全局變量。
我們再來理一下 (function(){var a = b = 5})() 表達式內(nèi)部整體的執(zhí)行順序:
1.匿名函數(shù)內(nèi)創(chuàng)建變量a;
2.賦予初始值undefined;
3.取得變量a的引用; //a
4.取得變量b的引用; //window.b
5.對數(shù)字5求值;
6.賦值5給b的引用:window.b;
7.返回b = 5的結(jié)果5給a的引用:a;
8.返回a = 5的結(jié)果5;
很明顯,中間的一個步驟使得變量 b 被聲明為全局變量,明白之后,我們不難找到代碼的優(yōu)化點:只需將變量 b 顯式聲明為局部變量:
復(fù)制代碼 代碼如下:
(function(){
var a,b;
a = b = 5;
})()
相關(guān)文章
JavaScript語句錯誤throw、try及catch實例解析
這篇文章主要介紹了JavaScript語句錯誤throw、try及catch實例解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-08-08
跨瀏覽器的 mouseenter mouseleave 以及 compareDocumentPosition的使用說明
昨天去 大牛 司徒正美 的blog 看博文 突然看到 關(guān)于 onmouseenter 和onmouseleave 兩個ie專有事件..2010-05-05
屏蔽IE彈出"您查看的網(wǎng)頁正在試圖關(guān)閉窗口,是否關(guān)閉此窗口"的方法
本篇文章主要是對屏蔽IE彈出"您查看的網(wǎng)頁正在試圖關(guān)閉窗口,是否關(guān)閉此窗口"的方法進行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助2013-12-12
從setTimeout看js函數(shù)執(zhí)行過程
這篇文章主要介紹了從setTimeout看js函數(shù)執(zhí)行過程,需要的朋友可以參考下2017-12-12

