首页 > 代码库 > JS当心隐式的强制转换

JS当心隐式的强制转换

JavaScript对类型错误出奇的宽容

3 + true;        // 4
null + 3;        // 3

运算符+(加号)的重载

运算符+既重载了数字相加,又重载了字符串连接操作。具体是数字相加还是字符串连接,取决于其参数的类型

2 + 3;                   // 5
‘hello‘ + ‘world‘        // ‘hello world‘

"2" + 3;                // "23"
1 + 2 + "3"             // "33"
1 + "2" + 3             // "123"
"abc" + true            // "abctrue"

对象转换为基本数据类型

对象可以被强制转换为基本数据类型,最常见的用法是转换为字符串。

"the Math object: " + Math;                 // "the Math object: [object Math]"
‘the JSON object‘ + JSON;                   // "the JSON object[object JSON]"

对象通过隐式地调用其自身的toString方法转换为字符串。对象也可以通过其valueOf方法转换为数字。

"J" + { toString: function() { return "S" } };          // "JS"
2 + { valueOf: function() { return 3 } };               // 5

当一个对象同时包含toString和valueOf方法时,JS通过盲目地选择valueOf方法而不是toString方法来解决这种含糊的情况

var objTo = {
    toString: function() {
        return "[object objTo]";
    },
    valueOf: function() {
        return 17;
    }
};
"3" + objTo, 3 + objTo, ‘object: ‘ + objTo        // 317, 20, object: 17

一般对象的字符串转换比数字的强制转换更常见、更有用。因此最好避免使用valueOf方法

特殊浮点值NaN

NaN不等于其自身。 一些操作会导致NaN值的产生。这里有些例子:

Math.sqrt(-2)
Math.log(-1)
0/0
parseFloat(‘foo‘)    

标准的库函数isNaN也不是很可靠,因为它带有自己的隐式强制转换,在测试其参数之前,会将参数转换为数字(isNaN函数的一个更精确的名称可能是coercesToNaN)。如果你已经知道一个值是数字,你可以使用isNaN函数测试它是否是NaN。

isNaN(NaN)             // true
isNaN(5)               // false
isNaN(true)            // false
isNaN(‘‘)              // false
isNaN(null)            // false
isNaN({ valueOf: function() { return 9 } })        // false

isNaN(‘foo‘)           // true
isNaN(undefined)       // true

因为true、‘‘、null及返回数字的对象,能强制转换成数字,所以测试为false

真值运算

if, ||及&&等运算符逻辑上需要布尔值作为操作参数,但实际上可以接受任何值。JS按照简单的隐式强制转换规则将值解释为布尔值。对于字符串和数字以外的其他对象,真值运算不会隐式调用任何强制转换方法。JS中有7个假值:false、0、-0、""、NaN、null、undefined。由于数字和字符串可能为假值,因此使用真值运算检查函数参数或者对象属性是否定义不是绝对安全的。例如,一个带有默认值的接受可选参数的函数:

var point = function(x, y) {
    if(!x) {
        x = 320;
    }
    if(!y) {
        y = 240;
    }
    return { x: x, y: y };
}

检查参数是否为undefined更为严格的方式是使用typeof

var point = function(x, y) {
    if(typeof x === ‘undefined‘) {
        x = 320;
    }
    if(typeof y === ‘undefined‘) {
        y = 240;
    }
    return { x: x, y: y };
}