1.7 自动类型转换
在前言中,我提到过JavaScript几乎可以接受你给它的任何程序,甚至是做奇怪事情的程序。以下表达式很好地证明了这一点:
当运算符应用于“错误”类型的值时,JavaScript将使用一组规则将此值默不作声地转换为所需的类型,但此规则通常不是你想要或期望的。这称为类型强制转换。第一个表达式中的null变为0,第二个表达式中的"5"变为5(从字符串到数字)。然而在第三个表达式中,+在数字加法之前尝试字符串连接,因此1被转换为"1"(从数字到字符串)。
当某些未以明显方式映射到数字的内容(例如"five"或undefined)转换为数字时,你将得到值NaN。对NaN的进一步算术运算会继续产生NaN,所以如果你在这些地方看到意想不到的结果,请找一下是否有意外的类型转换。
当使用==比较相同类型的值时,结果很容易预测:当两个值相同时,应该得到true,只有NaN除外。但是当类型不同时,JavaScript会使用一组复杂而混乱的规则来确定要执行的操作。在大多数情况下,它只是尝试将其中一个值转换为另一个值的类型。但是,如果在运算符的任一侧出现null或undefined,则仅当两侧都是null或undefined之一时才生成true。
这种行为通常很有用。如果要测试一个值是否具有实际值而不是null或undefined,则可以用==(或!=)运算符将其与null进行比较。
但是,如果你想测试某些东西是否指的是精确值false,该怎么办呢?表达式如0 ==false和""== false都是正确的。当你不希望发生任何自动类型转换时,可以用两个额外的运算符:===和!==。第一个测试一个值是否与另一个值完全相等,第二个测试它是否不完全相等。所以""=== false是错误的。
我建议使用三字符比较运算符,以防发生意外的类型转换。但是当你确定双方的类型相同时,就可以使用较短的运算符。
逻辑运算符的短路
逻辑运算符&&和||以一种特殊的方式处理不同类型的值。它们将按顺序将左侧的值转换为布尔类型,以决定做什么,再根据运算符及转换结果,返回原始的左侧值或右侧值。
例如,如果||运算符左侧的值能转换为true,它就返回左侧的值,否则返回其右侧的值。当值为布尔值时,这具有预期的效果,并且对于其他类型的值也执行类似的操作。
我们可以使用此功能作为返回默认值的方法。如果你的值可能为空,则可以在它之后放一个||,再跟一个替换值。如果初始值可以转换为false,那么你将得到替换值。将字符串和数字转换为布尔值的规则规定:0、NaN和空字符串("")计为false,而所有其他值都计为true。所以0 || -1产生-1,而"" || "! ? "得到"! ? "。
&&运算符的工作方式与||类似,但结果相反。当左侧的值能转换为false值时,它返回左侧的值,否则返回右侧的值。
这两个运算符的另一个重要特性是,只有在必要时,才计算其右侧的部分。例如true|| X,无论X是什么——即使它是一个做一些糟糕事情的程序——结果也是true,而X永远不会被计算。对于false && X也是如此,结果是false并且将忽略X。这称为短路计算(short-circuit evaluation)。
条件运算符以类似的方式工作。在第二个和第三个值中,仅计算所选的那一个。