DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> 容易被忽略的JS腳本特性
容易被忽略的JS腳本特性
編輯:關於JavaScript     
一、容易被忽略的局部變量
復制代碼 代碼如下:
var a = 5;
(function(){
alert(a);
var a = a ++;
alert(a);
})()
alert(a);

思考這段代碼的執行結果。
執行後,看看是否和你想象的一致?
ok,這段代碼裡核心的知識點是 var a = a++,其中兩個變量 a 都是匿名函數內部的局部變量,是同一個,和全局變量 a 是不一樣的。
為什麼?我們來看看ECMA規范對變量聲明語句的定義:
復制代碼 代碼如下:
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.

聲明中提到:進入作用域環境後,變量就會被創建,並賦予初始值undefined。在變量聲明語句執行時才會把賦值表達式的值指派給該變量,而並不是在該變量被創建時。
因此上面的代碼可以等價於:
復制代碼 代碼如下:
var a;
a = 5;
(function(){
var a;
alert(a);
a = a ++;
alert(a);
})()
alert(a);

這樣應該會更容易理解了。
二、容易被忽略的全局變量
復制代碼 代碼如下:
(function(){
var a = b = 5;
})()
alert(b);

這是玉伯幾天前分享到的知識點,蠻有意義的,在此也做個分析。
首先,考慮執行結果為什麼是:5。
ok,原因出在 var a = b = 5 這句。
為深入分析這個語句,我們繼續要參照ECMA規范對聲明語句的定義:
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;先執行左邊表達式 a,這是一個標識符表達式,根據規范第 10.1.4,其執行方式如下:
復制代碼 代碼如下:
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 的引用,很明顯,在匿名函數內部作用域就可以找到,於是變量 a 確定下來。
接著再執行右邊的表達式 b = 5 ,還是一個賦值表達式,重復賦值規則第一步,因為變量 b 在匿名函數環境內未聲明過,所以接著去 window 全局環境下去找 window.b ,被隱式聲明為全局變量,最後賦值為 5,根據規則第五步,表達式的結果也會再賦值給 a。最終達到 a 和 b 都為 5 ,區別是 a 是局部變量,而 b 是全局變量。
我們再來理一下 (function(){var a = b = 5})() 表達式內部整體的執行順序:
1.匿名函數內創建變量a;
2.賦予初始值undefined;
3.取得變量a的引用; //a
4.取得變量b的引用; //window.b
5.對數字5求值;
6.賦值5給b的引用:window.b;
7.返回b = 5的結果5給a的引用:a;
8.返回a = 5的結果5;
很明顯,中間的一個步驟使得變量 b 被聲明為全局變量,明白之後,我們不難找到代碼的優化點:只需將變量 b 顯式聲明為局部變量:
復制代碼 代碼如下:
(function(){
var a,b;
a = b = 5;
})()
XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved