容易被忽略的JS指令碼特性

來源:互聯網
上載者:User

一、容易被忽略的局部變數
複製代碼 代碼如下:
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;
})()

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.