我见的太多了,JS 代码里面 Js-Lint 警告被置之不理。最多的估计是花括号和分号的缺失了,另外有很大一部分是滥用 == 来做以下比较:

  • x == false
  • x == null
  • x == undefined
  • x == 0
  • x == ""
  • x == 1
  • x == true

其实这些比较实在很没必要,关键是还很不安全,往往这会给维护的人(哪怕是原作者本人)带来疑惑:究竟你的意图是真的要和这些值做比较呢,还是只要真或假就可以了?更糟糕的是,这样的比较往往会产生意想不到的后果。

我用以下代码产生了几张表格:

// js
var falsyArr = [false, 0, NaN, null, undefined, "", "0", " trn "],
    ifArr = [],
    compareArr = [],
    i, j,
    getFalsyDisplay = function(falsy) {
        switch (falsy) {
        case null:
            return "null";
        case "":
            return "\"\"";
        case "0":
            return "\"0\"";
        case " trn ":
            return "\" \t\r\n \"";
        default:
            return falsy;
        }
    };

for (i = 0; i < falsyArr.length; i++) {
    var iArr = [];
    for (j = 0; j < falsyArr.length; j++) {
        iArr.push({
            "==": falsyArr[i] == falsyArr[j],
            "!=": falsyArr[i] != falsyArr[j],
            "===": falsyArr[i] === falsyArr[j],
            "!==": falsyArr[i] !== falsyArr[j]
        });
    }
    ifArr.push(falsyArr[i] ? true : false);
    compareArr.push(iArr);
}

var createTbl = function(comp) {
    var id, tbl, row, cell;
    switch (comp) {
    case "==":
        id = "eqeq";
        break;
    case "!=":
        id = "noteq";
        break;
    case "===":
        id = "eqeqeq";
        break;
    case "!==":
        id = "noteqeq";
        break;
    default:// if
        id = "if";
        break;
    }

    tbl = document.getElementById(id);
    if (tbl) {
        tbl.parentNode.removeChild(tbl);
    }

    tbl = document.createElement("table");
    tbl.id = id;
    row = tbl.insertRow(0);
    cell = document.createElement("th");
    cell.innerHTML = getFalsyDisplay(comp || id);
    cell.style.color = "#F30";
    row.appendChild(cell);

    for (i = 0; i < falsyArr.length; i++) {
        cell = document.createElement("th");
        cell.innerHTML = getFalsyDisplay(falsyArr[i]);
        row.appendChild(cell);
    }

    document.body.appendChild(tbl);
    return tbl;
}, createCompareTbl = function(comp) {
    var tbl = createTbl(comp), row, cell;

    for (i = 0; i < falsyArr.length; i++) {
        row = tbl.insertRow(i + 1);

        cell = document.createElement("th");
        cell.innerHTML = getFalsyDisplay(falsyArr[i]);
        row.appendChild(cell);

        for (j = 0; j < falsyArr.length; j++) {
            cell = row.insertCell(j + 1);
            if (i <= j) {
                cell.innerHTML = compareArr[i][j][comp] ? "Y" : "N";
                cell.className = compareArr[i][j][comp];
            }
        }
    }
}, createIfTbl = function() {
    var tbl = createTbl(),
        row = tbl.insertRow(1),
        cell = document.createElement("th");

    row.appendChild(cell);
    for (i = 0; i < falsyArr.length; i++) {
        cell = row.insertCell(i + 1);
        cell.innerHTML = ifArr[i] ? "Y" : "N";
        cell.className = ifArr[i];
    }
};
createIfTbl();
createCompareTbl("==");
createCompareTbl("===");
createCompareTbl("!=");
createCompareTbl("!==");
/* css */
body {
    padding: 0;
    margin: 0;
}
table#eqeq,
table#noteq,
table#eqeqeq,
table#noteqeq,
table#if {
    table-layout: fixed;
    width: 630px;
}
table#eqeq th,
table#eqeq td,
table#noteq th,
table#noteq td,
table#eqeqeq th,
table#eqeqeq td,
table#noteqeq th,
table#noteqeq td,
table#if th,
table#if td {
    text-align: center;
    font-size: 9pt;
    font-family: Arial;
}
table#eqeq th,
table#noteq th,
table#eqeqeq th,
table#noteqeq th,
table#if th {
    background-color: #DDD;
}
table#eqeq td,
table#noteq td,
table#eqeqeq td,
table#noteqeq td,
table#if td {
    background-color: #EEE;
}
table#eqeq td.true,
table#noteq td.true,
table#eqeqeq td.true,
table#noteqeq td.true,
table#if td.true {
    background-color: #CFC;
}
table#eqeq td.false,
table#noteq td.false,
table#eqeqeq td.false,
table#noteqeq td.false,
table#if td.false {
    background-color: #FCC;
}

首先最奇怪的是 NaN,众所周知了,它与任何东西都不相等,甚至自己都不等于自己。

然后奇怪的是 nullundefined,它们是假值,互相之间可以 ==,但不等于 false,更不等于 true

然后是 "0"" \t\r\n " 这两个亦真亦假的值,if 判断的时候 "0"" \t\r\n " 都为真,但是它们却 == false,再试一下 "0" == true" \t\r\n " == true,结果返回的是 false…悖论 - 以假乱真?

假的东西在 if 的时候是真的,事实上它们是应该为真,但是再跟 true / false 做比较的时候,万恶的解释器对他们做了类型转换:

  1. 先把 Stringtrim
  2. 然后
    • 空串则 == false
    • 非空串,转换成数字,为 0== false

所以,就有了如下的奇葩结果:

  • "0" == false
  • " 0" == false
  • \t\r\n00000000000 == false

在数学里,我们有 A == B, B == C ⇒ A == C,数学是严谨的,但 JS 不是,在这里,你很有可能得出这样的结论:A == B, B == C ⇒ A != C,比如:"0" == 0, 0 == "" ⇒ "0" != ""。这也是类型转换造成的,"0" == 0 会把后面的 0 toString() 转成 String 型,0 == "" 则会把两个都转成 Boolean 型,而 "0" == "" 因为两个都是 String 型所以无需转换,就不等了。

其实要避免这种错误的类型转换很简单,一个就是尽量用 ===!==,另外就是用 if (!x) 代替 if (x == false)if (x) 代替 if (x == true) 之类的语句。

不要无所谓,尽量让你的 JS 变成 Js-Lint Warn-Free 吧,对你对项目都是有好处的。