[譯]JavaScript中的變量聲明:你可以打破的三條規則


原文:http://www.2ality.com/2012/11/var-statement-rules.html


本文提到了在使用var語句時經常被提到的三條規則,然后告訴你什么時候我們可以打破這些規則.在閱讀本文之前,你必須已經了解了JavaScript中函數作用域內的var聲明是如何工作的 [1] .

1.你可以打破的三條規則

1.1. 要打破的規則:不要把var語句放在代碼塊中

以常規看法來說,下面的代碼是不好的:

// 非常規寫法
function foo(x, y) {
    if (x > y) {
        var tmp = x;
        x = y;
        y = tmp;
    }
    ...
}

為什么說是不好的: 看到這樣的代碼,也許有人會認為變量tmp只存在於if語句塊中.而實際情況是,變量tmp的聲明會被提升,也就是說變量tmp的聲明操作實際上是在函數的最開始處,而賦值操作還留在原來語句存在的地方.因此,下面的寫法更能反應出JavaScript引擎內部實際上看到的代碼(預解析之后):

// 常規寫法
function foo(x, y) {
    var tmp;
    if (x > y) {
        tmp = x;
        x = y;
        y = tmp;
    }
    ...
}

反對觀點: 從JavaScript語義的角度看,變量tmp不僅僅存在於if語句塊中.可是,從概念上講,tmp被限制在了那個語句塊中:別的地方沒有用到它,如果有人刪除了這個if語句塊,tmp的聲明操作也應該被刪除.這樣的話,非常規寫法能更好的表現出作者的意圖.

對於函數體很長的函數來說,常規寫法是對的.可是,一個函數的行數不應該長於5-10行,這種長度下的話,增加概念上的清晰度更值得考慮.

1.2.要打破的規則: 不要把var語句放在循環體中

常規看法告訴我們: 不要像下面這樣寫.

// 非常規寫法
for (var i = 0; i < 10000; i++) {
    var foo = 1;
}

說是下面這樣的寫法會更快點:

// 常規寫法
var foo; for (var i = 0; i < 10000; i++) { foo = 1; }

可是,常規看法是不對的,在一些引擎中,常規寫法甚至更慢,這個jsPerf測試就能證明:這兩種寫法並沒有明顯的性能差異.

1.3.要打破的規則: 每個函數都使用單一的var語句

常規看法告訴我們:你應該把所有的變量聲明都放在函數體開始的地方,而且僅能使用一條var語句.例如:

// 常規寫法
var foo = 1,
    bar = 2,
    baz = 3;

這么規定有兩個原因.首先,這樣寫可以防止變量提升(hoisting)帶來的詭異問題.其次,還可以避免重復的var關鍵字.

我們前面已經提到一個比防止變量提升更值得考慮的事情.

避免重復的var會產生一個負面效應:就是如果你漏掉一個逗號,你會意外的創建一些全局變量.例如:

var foo = 1  // 沒有逗號
    bar = 2,
    baz = 3;

因為在1和bar之間是由換行符分割的,JavaScript引擎會自動在換行符前面插入一個分號 [2]. 因此,后面的兩行就成為了一個只包含了bar和baz賦值操作的逗號表達式語句,在非嚴格模式中,這意味着會創建兩個全局變量.如果同樣的代碼運行在嚴格模式中 [3]:

(function () {
    "use strict";
    var foo = 1
        bar = 2,
        baz = 3;
}());

會拋出異常:我們為一個不存在的變量執行了賦值操作:

ReferenceError: bar is not defined

與其使用單獨的var語句聲明多個變量,我更推薦下面的方式:

var foo = 1;
var bar = 2;
var baz = 3;

這種方式有幾個優點:

  • 忘記標點符號不會引發問題. 如果忘記寫分號,自動分號插入(ASI)會幫助你,而不是為難你.
  • 更方便修改代碼和刪除部分變量的賦值操作.
  • 不需要縮進.

2. ECMAScript 6

ECMAScript 6中將會引入塊級作用域下的變量聲明(通過let語句).另外,還會增加解構賦值(destructuring assignment)語法:在賦值運算符左側可以訪問到右側數據的內部結構.使用解構賦值可以省去在1.1小節中的函數foo中的臨時變量的使用,會讓代碼更簡潔:

function foo(x, y) {
    if (x > y) {
        [y, x] = [x, y];
    }
    ...
}

3. 結論

本文我們討論了三個關於var語句的,可以打破而且也經常需要打破的規則.和往常一樣,不要盲目的聽從任何人的建議(包括那些常規的看法以及本文給出的看法),要確保自己真的知道自己在干什么.

4. 參考

  1. JavaScript variable scoping and its pitfalls
  2. Automatic semicolon insertion in JavaScript
  3. JavaScript’s strict mode: a summary


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM