容易被忽略的JS腳本特性
更新時(shí)間: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,這段代碼里核心的知識(shí)點(diǎn)是 var a = a++,其中兩個(gè)變量 a 都是匿名函數(shù)內(nèi)部的局部變量,是同一個(gè),和全局變量 a 是不一樣的。
為什么?我們來(lái)看看ECMA規(guī)范對(duì)變量聲明語(yǔ)句的定義:
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.
聲明中提到:進(jìn)入作用域環(huán)境后,變量就會(huì)被創(chuàng)建,并賦予初始值undefined。在變量聲明語(yǔ)句執(zhí)行時(shí)才會(huì)把賦值表達(dá)式的值指派給該變量,而并不是在該變量被創(chuàng)建時(shí)。
因此上面的代碼可以等價(jià)于:
var a;
a = 5;
(function(){
var a;
alert(a);
a = a ++;
alert(a);
})()
alert(a);
這樣應(yīng)該會(huì)更容易理解了。
二、容易被忽略的全局變量
(function(){
var a = b = 5;
})()
alert(b);
這是玉伯幾天前分享到的知識(shí)點(diǎn),蠻有意義的,在此也做個(gè)分析。
首先,考慮執(zhí)行結(jié)果為什么是:5。
ok,原因出在 var a = b = 5 這句。
為深入分析這個(gè)語(yǔ)句,我們繼續(xù)要參照ECMA規(guī)范對(duì)聲明語(yǔ)句的定義:
var a = b = 5;等同為 var a; a = b = 5;兩條語(yǔ)句,后者是賦值表達(dá)式,其在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).
對(duì)于a = b = 5;先執(zhí)行左邊表達(dá)式 a,這是一個(gè)標(biāo)識(shí)符表達(dá)式,根據(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.
搜尋作用域鏈,找到最近的一個(gè) a 的引用,很明顯,在匿名函數(shù)內(nèi)部作用域就可以找到,于是變量 a 確定下來(lái)。
接著再執(zhí)行右邊的表達(dá)式 b = 5 ,還是一個(gè)賦值表達(dá)式,重復(fù)賦值規(guī)則第一步,因?yàn)樽兞?b 在匿名函數(shù)環(huán)境內(nèi)未聲明過(guò),所以接著去 window 全局環(huán)境下去找 window.b ,被隱式聲明為全局變量,最后賦值為 5,根據(jù)規(guī)則第五步,表達(dá)式的結(jié)果也會(huì)再賦值給 a。最終達(dá)到 a 和 b 都為 5 ,區(qū)別是 a 是局部變量,而 b 是全局變量。
我們?cè)賮?lái)理一下 (function(){var a = b = 5})() 表達(dá)式內(nèi)部整體的執(zhí)行順序:
1.匿名函數(shù)內(nèi)創(chuàng)建變量a;
2.賦予初始值undefined;
3.取得變量a的引用; //a
4.取得變量b的引用; //window.b
5.對(duì)數(shù)字5求值;
6.賦值5給b的引用:window.b;
7.返回b = 5的結(jié)果5給a的引用:a;
8.返回a = 5的結(jié)果5;
很明顯,中間的一個(gè)步驟使得變量 b 被聲明為全局變量,明白之后,我們不難找到代碼的優(yōu)化點(diǎn):只需將變量 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,這段代碼里核心的知識(shí)點(diǎn)是 var a = a++,其中兩個(gè)變量 a 都是匿名函數(shù)內(nèi)部的局部變量,是同一個(gè),和全局變量 a 是不一樣的。
為什么?我們來(lái)看看ECMA規(guī)范對(duì)變量聲明語(yǔ)句的定義:
復(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.
聲明中提到:進(jìn)入作用域環(huán)境后,變量就會(huì)被創(chuàng)建,并賦予初始值undefined。在變量聲明語(yǔ)句執(zhí)行時(shí)才會(huì)把賦值表達(dá)式的值指派給該變量,而并不是在該變量被創(chuàng)建時(shí)。
因此上面的代碼可以等價(jià)于:
復(fù)制代碼 代碼如下:
var a;
a = 5;
(function(){
var a;
alert(a);
a = a ++;
alert(a);
})()
alert(a);
這樣應(yīng)該會(huì)更容易理解了。
二、容易被忽略的全局變量
復(fù)制代碼 代碼如下:
(function(){
var a = b = 5;
})()
alert(b);
這是玉伯幾天前分享到的知識(shí)點(diǎn),蠻有意義的,在此也做個(gè)分析。
首先,考慮執(zhí)行結(jié)果為什么是:5。
ok,原因出在 var a = b = 5 這句。
為深入分析這個(gè)語(yǔ)句,我們繼續(xù)要參照ECMA規(guī)范對(duì)聲明語(yǔ)句的定義:
var a = b = 5;等同為 var a; a = b = 5;兩條語(yǔ)句,后者是賦值表達(dá)式,其在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).
對(duì)于a = b = 5;先執(zhí)行左邊表達(dá)式 a,這是一個(gè)標(biāo)識(shí)符表達(dá)式,根據(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.
搜尋作用域鏈,找到最近的一個(gè) a 的引用,很明顯,在匿名函數(shù)內(nèi)部作用域就可以找到,于是變量 a 確定下來(lái)。
接著再執(zhí)行右邊的表達(dá)式 b = 5 ,還是一個(gè)賦值表達(dá)式,重復(fù)賦值規(guī)則第一步,因?yàn)樽兞?b 在匿名函數(shù)環(huán)境內(nèi)未聲明過(guò),所以接著去 window 全局環(huán)境下去找 window.b ,被隱式聲明為全局變量,最后賦值為 5,根據(jù)規(guī)則第五步,表達(dá)式的結(jié)果也會(huì)再賦值給 a。最終達(dá)到 a 和 b 都為 5 ,區(qū)別是 a 是局部變量,而 b 是全局變量。
我們?cè)賮?lái)理一下 (function(){var a = b = 5})() 表達(dá)式內(nèi)部整體的執(zhí)行順序:
1.匿名函數(shù)內(nèi)創(chuàng)建變量a;
2.賦予初始值undefined;
3.取得變量a的引用; //a
4.取得變量b的引用; //window.b
5.對(duì)數(shù)字5求值;
6.賦值5給b的引用:window.b;
7.返回b = 5的結(jié)果5給a的引用:a;
8.返回a = 5的結(jié)果5;
很明顯,中間的一個(gè)步驟使得變量 b 被聲明為全局變量,明白之后,我們不難找到代碼的優(yōu)化點(diǎn):只需將變量 b 顯式聲明為局部變量:
復(fù)制代碼 代碼如下:
(function(){
var a,b;
a = b = 5;
})()
相關(guān)文章
javascript數(shù)組克隆簡(jiǎn)單實(shí)現(xiàn)方法
這篇文章主要介紹了javascript數(shù)組克隆簡(jiǎn)單實(shí)現(xiàn)方法,實(shí)例分析了JavaScript中concat用于數(shù)組克隆的使用技巧,需要的朋友可以參考下2015-12-12javascript解決innerText瀏覽器兼容問(wèn)題思路代碼
innerText瀏覽器兼容這塊始終都是一個(gè)問(wèn)題,下面與大家分享下使用javascript解決,感興趣的朋友可以參考下哈,希望對(duì)你有所幫助2013-05-05javascript實(shí)現(xiàn)文字無(wú)縫滾動(dòng)
這篇文章主要介紹了javascript實(shí)現(xiàn)文字無(wú)縫滾動(dòng),文字可以實(shí)現(xiàn)上下滾動(dòng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12JS如何調(diào)用WebAssembly編譯出來(lái)的.wasm文件
這篇文章主要介紹了關(guān)于WebAssembly編譯出來(lái)的.wasm文件js如何調(diào)用,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11javascript實(shí)現(xiàn)簡(jiǎn)單打字游戲
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)簡(jiǎn)單打字游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10