可能被你忽略的 JavaScript 代碼陷阱

下面這段代碼,你知道有哪些錯誤嗎:



請仔細思考後再往下閱讀。

—- 幫助你思考的刷屏線 開始 —-

—- 幫助你思考的刷屏線 結束 —-

1. isLive = config.isLive || true, 當傳入的值有可能就是0, undefined, null, false, "", NaN這六個 falsy 值時,用 || 來設定默認值不妥當。更保險的做法是:

isLive = "isLive" in config ? config.isLive : true;

如果是獨立變量,可以採用:

someVar = typeof someVar !== "undefined" ? someVar : defaultValue;

注意:大部分情況下,用 || 已經夠用,比如:

container = container || document
name = config.name || "無名氏"

一切皆權衡。

2. var g_bar = g_bar || "", 原意是取全局變量 g_bar 的值給內部變量 g_bar, 默認爲空字符串。然而,實際情況等價爲:

var g_bar;
g_bar = g_bar || "";

很明顯,|| 號左邊的 g_bar 也是內部變量,並且爲 undefined, 因此var g_bar = g_bar || ""實際上是var g_bar = "", 沒有滿足代碼的原始意圖。

思考:代碼中的var container = container || document有無問題?爲什麼?

3. if(g_foo) { /* code */ }, 這段代碼在執行時會報錯。我們都知道在 JS 裏,變量不定義就可以用。但一定要清楚,未定義的變量,僅僅是可寫,但不可讀。比如:

g_foo = 2; // 等價 window.g_foo = 2
var t = g_foo2; // 不等價爲 var t = window.g_foo2, 會報錯

具體原因可以參見 JavaScript 運行機制淺探

    未定義變量意味着在 scriptObject 的變量表中找不到,JS 引擎會沿着 scriptObject 的 upvalue 往上尋找,如果都沒找到,對於寫操作 i = 1; 最後就會等價爲 window.i = 1; 給 window 對象新增了一個屬性。對於讀操作,如果一直追溯到全局執行環境的 scriptObject 上都找不到,就會產生運行期錯誤。

因此嚴謹的寫法是:

if(window.g_foo) {
    /* your code */
}

不要小看這些細微之處,有時會讓人抓狂的。但這些細微之處又很容易被忽略或濫用。比如 YUI 2.8r4 裏,有一個遺傳了很久的 bug:

var NOTHING = [];
// ....
later: function(when, o, fn, data, periodic) {
    when = when || 0;
    o = o || {};
    var m = fn, d = data, f, r;
    // ...
    if (d && !L.isArray(d)) {
        d = [data];
    }

    f = function() {
        m.apply(o, d || NOTHING);
    };
    // ...
}

當你的調用代碼類似Lang.later(delay[0], o, "show", index)時,如果 index 不幸是 base-0 的,那麼取 0 時, m.apply(o, d || NOTHING)會讓你得到“驚喜”。更妥的做法是類似 YUI3 中的修正:

// ...
if (!L.isArray(d)) {
    d = [data];
}?

f = function() {
    m.apply(o, d);
};
//...

對於 || 和 && 的用法,很多 JS 書籍(無論中外),都用來片面強調 JS 的靈活性,包括 Douglas 的《JavaScript The Good Parts》中也存在誤導。

最後,有感於 NCZ 今天寫的 Writing Maintainable Code , 再舉一例(和本文主題關係不明顯,但的確又有關係,交給你去思考囉):

var isBoy = true;
isBoy = typeof isGirl !== "undefined" ? !isGirl : true;

或者來個耍酷的代碼:

var isBoy = true;
(typeof isGirl !== "undefined") && (isBoy =  !isGirl);

然而,以上兩種寫法,無論從代碼長度還是性能上講,都不如更直白的寫法:

var isBoy = true;
if(typeof isGirl !== "undefined") isBoy =  !isGirl;

簡單質樸,往往是最好的。

 

轉自:http://lifesinger.org/blog/2009/12/easy-ignorable-js-code/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章