真值、相等以及JavaScript

即便你不是一个JavaScript的新手也会被下面这段代码搞糊涂

if ([0]) {
    console.log([0] == true); //false
    console.log(!![0]); //true
}

或者像这样的

if ("potato") {
    console.log("potato" == false); //false
    console.log("potato" == true); //false
}

好消息是,我们有一个所有浏览器都遵循的标准。有些作者会告诉你要小心强制 转换,并且在编码的时候要避免这种情况。我希望能说服你,强换是一种可被利用的特点(或者说在最低可被理解的条件下),而不是避免。

x的值为真吗?x和y是否相等?真值和相等判断是JavaScript三个主要领域的核心:条件语句和操作符(if,三目,&&,||等等……),相等操作符( == ),以及强等于操作符( === )。让我们看看再每种情况下会发生什么……

条件语句

在JavaScript中,所有的条件语句和操作符遵循同样的强制转换模式。我们将用if语句作为例子。

if(表达式)语句结构将会使用抽象方法ToBoolean把表达式的运算结果强转成一个布尔值。为了实现这个抽象方法,ES5定义了如下算法:

Argument TypeResult
Undefinedfalse
Nullfalse
BooleanThe result equals the input argument (no conversion).
NumberThe result is false if the argument is +0, −0, or NaN;
otherwise the result is true.
StringThe result is false if the argument is the empty String (its length is zero);
otherwise the result is true.
Objecttrue.

这是javascript用来把值分为真值(true,“potato”,36,[1,2,3]以及{a:16})和假值(false,0,"",null以及undefined)的公式。

现在我们明白了为什么在介绍性的例子中,if([0])允许进入随后的块:一个数组是一个对象,所有的对象被转换成true

这里还有几个例子。一些结果可能令人惊讶,但它们总是遵循上面指定的简单规则:

var trutheyTester = function(expr) {
    return expr ? "truthey" : "falsey"; 
}
 
trutheyTester({}); //truthey (an object is always true)
 
trutheyTester(false); //falsey
trutheyTester(new Boolean(false)); //truthey (an object!)
 
trutheyTester(""); //falsey
trutheyTester(new String("")); //truthey (an object!)
 
trutheyTester(NaN); //falsey
trutheyTester(new Number(NaN)); //truthey (an object!)
相同操作符(==)

判等的 == 版本是相当自由的。即使它们是不同的类型,值也可以被认为是相等的,因为操作符在进行比较之前,会强制将一个或两个操作数强制转换为单个类型(通常是一个数字)。许多开发人员发现这有点吓人,毫无疑问,至少有一个著名的JavaScript专家建议完全避免使用== 操作符。

回避策略困扰着我,因为在你完全了解一门语言之前,你无法掌握它——恐惧和逃避是知识的敌人。此外,假装 == 不存在不会让你在理解强制转换时摆脱困境,因为JavaScript中强制转换无处不在!它在条件表达式中(正如我们刚才看到的),它在数组索引中,它在连接符中等等。此外,如果安全地使用,强制转换可以成为编写简洁、优雅以及易读代码的工具。

不管怎样,我们来看看ECMA是如何定义 == 的。它真的没有那么吓人。只要记住,undefinednull是相等的(没有别的),大多数其他类型都被强制转换成一个数字来进行比较:

Type(x)Type(y)Result
x and y are the same typeSee Strict Equality (===) Algorithm
nullUndefinedtrue
Undefinednulltrue
NumberStringx == toNumber(y)
StringNumbertoNumber(x) == y
Boolean(any)toNumber(x) == y
(any)Booleanx == toNumber(y)
String or NumberObjectx == toPrimitive(y)
ObjectString or NumbertoPrimitive(x) == y
otherwise…false

在结果是表达式的地方,算法被重新应用,直到结果是布尔值。toNumber 和 toPrimitive是内部方法,用来根据下面的规则进行转换:

ToNumber
参数类型结果
UndefinedNaN
Null+0
Boolean如果参数为 true,结果 1
如果参数为 false,结果 +0
Number结果即为输入的参数 (不转换)。
StringNumber(string) 的实际计算结果
“abc” -> NaN
“123” -> 123
Object应用下面的步骤:

1. Let primValue be ToPrimitive(input argument, hint Number).
2. Return ToNumber(primValue).

ToPrimitive
Argument TypeResult
Object(在相等运算符强转的条件下) 如果valueOf 返回一个基本类型, 那么返回它。 否则,如果 toString 返回的是基本类型,那么返回 toString的值。如果都不是,抛出异常。
otherwise…结果等于输入的参数 (不转换)。

这里有一些例子,我将使用伪代码一步一步地演示如何应用强制转换算法:

[0] == true;
//EQUALITY CHECK...
[0] == true; 
 
//HOW IT WORKS...
//convert boolean using toNumber
[0] == 1;
//convert object using toPrimitive
//[0].valueOf() is not a primitive so use...
//[0].toString() -> "0"
"0" == 1; 
//convert string using toNumber
0 == 1; //false!
“potato” == true;
//EQUALITY CHECK...
"potato" == true; 
 
//HOW IT WORKS...
//convert boolean using toNumber
"potato" == 1;
//convert string using toNumber
NaN == 1; //false!
“potato” == false;
//EQUALITY CHECK...
"potato" == false; 
 
//HOW IT WORKS...
//convert boolean using toNumber
"potato" == 0;
//convert string using toNumber
NaN == 0; //false!
object with valueOf
//EQUALITY CHECK...
crazyNumeric = new Number(1); 
crazyNumeric.toString = function() {return "2"}; 
crazyNumeric == 1;
 
//HOW IT WORKS...
//convert object using toPrimitive
//valueOf returns a primitive so use it
1 == 1; //true!
object with toString
//EQUALITY CHECK...
var crazyObj  = {
    toString: function() {return "2"}
}
crazyObj == 1; 
 
//HOW IT WORKS...
//convert object using toPrimitive
//valueOf returns an object so use toString
"2" == 1;
//convert string using toNumber
2 == 1; //false!
严格相等操作符(===)

这个很简单。如果操作数是不同类型那么结果永远为false。如果它们属于同一类型,则应用直觉相等测试:对象标识符必须引用相同的对象,字符串必须包含相同的字符集,其他的基本类型必须持有相等的值。NaNnullundefined 彼此互不相等。NaN甚至不会 === 自己。

Type(x)ValuesResult
Type(x) different from Type(y)false
Undefined or Nulltrue
Numberx same value as y (but not NaN)true
Stringx and y are identical characterstrue
Booleanx and y are both true or both falsetrue
Objectx and y reference same objecttrue
otherwise…false
过度使用强等判断的一些例子
//unnecessary
if (typeof myVar === "function");
 
//better
if (typeof myVar == "function");

由于typeOf返回一个字符串,所以这个操作总是比较两个字符串。因此== 100% 通过强制检验。

//unnecessary
var missing =  (myVar === undefined ||  myVar === null);
 
//better
var missing = (myVar == null);

null 和 undefined == 它们自己并且两者相等。

注意: 由于undefined存在被重定义的风险(非常小,将其等同于null会稍微安全一些。

//unnecessary
if (myArray.length === 3) {//..}
 
//better
if (myArray.length == 3) {//..}

前面说的已经够多了。

原文链接:https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值