在JavaScript中如何1 == ?
最近我在接受采访时被问到这个问题。
var a = 1; var b = [1];
什么将a == b;
返回。
当我在我的Chrome浏览器控制台上查看时,我得到了这个。
var a = 1; var b = [1]; a == b; true
我也检查过
var a = 1; var b =(1); a == b; true
我知道b是一个大小为1的数组。这是否意味着数组的大小被分配给b。 我真的很困惑。 任何人都可以解释我的逻辑?
如果一个对象与一个数字或string进行比较,JavaScript会尝试返回该对象的默认值。 运算符尝试使用对象的
valueOf
和toString
方法将对象转换为原始值(String
或数值)。 如果尝试转换对象失败,则会生成运行时错误。[ Ref ]
var a = 1; var b = [1]; //What is happening when `(a==b)` //typeof a; ==> number //typeof b; ==>object //Object is converted to Primitive using `valueOf` and `toString` methods of the objects var val = b.valueOf().toString(); console.log('Values after conversion is: ' + val + ' And typeof converted value is: ' + typeof val); //typeof val; ==> string //a == b; will be evaluated as `true` because `'1' == 1` hence.. console.log(a == b); //'1'==1 ==> true
我从Rayon的回答中并没有真正理解valueOf
和toString
如何在将对象转换为原始值时发挥作用; 所以我深入研究了ECMAScript 2015规范。
警告 :长答案。
我们要检查expression式1 == [1]
。
从12.10等式操作符开始,我们看到,在检索expression式值之后,最后一步是
- 返回执行抽象平等比较rval == lval的结果
抽象平等比较在第7.2.12章“ 抽象平等比较”中定义。
7.2.12摘要平等比较
比较x == y,其中x和y是值,产生true或false。 这样的比较如下进行:
- ReturnIfAbrupt(X)。
- ReturnIfAbrupt(Y)。
- 如果types(x)与types(y)相同,则
一个。 返回执行严格平等比较x === y的结果。- 如果x为null且y未定义,则返回true。
- 如果x未定义且y为null,则返回true。
- 如果Type(x)是Number和Type(y)是String,则返回比较结果x == ToNumber(y)。
- 如果Type(x)是String而Type(y)是Number,则返回比较结果ToNumber(x)== y。
- 如果Type(x)是布尔型,则返回比较结果ToNumber(x)== y。
- 如果Type(y)是布尔型,则返回比较结果x == ToNumber(y)。
- 如果Type(x)是String,Number或Symbol且Type(y)是Object,则返回比较结果x == ToPrimitive(y)。
- 如果Type(x)是Object且Type(y)是String,Number或Symbol,则返回比较结果ToPrimitive(x)== y。
- 返回false。
expression式1 == [1]
属于情况10 。
所以基本上,正如所料,数组[1]
被转换为原始types的值。
ToPrimitive定义在7.1.1 ToPrimitive(input [,PreferredType])
抽象操作ToPrimitive接受一个input参数和一个可选的参数PreferredType。 抽象操作ToPrimitive将其input参数转换为非对象types。
我没有包括完整的引文, 因为这个例子中唯一有趣的部分是:
- PreferredType参数(实际上是一个提示variables)从“默认”(因为它不被传递)转换为“数字”。
-
OrdinaryToPrimitive
被调用相同的参数。
E现在有趣的部分, OrdinaryToPrimitive做到以下几点:
- 断言:types(O)是对象
- 断言:types(提示)是string,其值是“string”或“数字”。
- 如果提示是“string”,那么
一个。 让methodNames成为«“toString”,“valueOf”»。- 其他,
一个。 让methodNames是«“valueOf”,“toString”»。- 对于列表顺序中的methodNames中的每个名称,请执行
一个。 让方法是Get(O,名称)。
湾 ReturnIfAbrupt(方法)。
C。 如果IsCallable(method)是真的,那么
… 一世。 让结果被调用(方法,O)。
ii。 ReturnIfAbrupt(结果)。
iii。 **如果Type(结果)不是Object,则返回结果。 **- 抛出一个TypeErrorexception
所以为了将[1]
转换为原始值,运行时首先要调用valueOf
。 这个方法返回数组本身,这是一个对象,所以通过5.c.iii方法toString
被下一个调用。
此方法以逗号分隔列表的forms返回数组的元素,所以它只返回string"1"
。
所以我们减less比较1 == "1"
,根据抽象平等比较的规则,点6,意味着将"1"
转换为数字1
而不是执行平凡的比较1 = 1
。
邀请可疑读者检查严格平等比较是如何在标准中实际定义的。
你可以玩转换为更好的理解他们,在这里一个示例游乐场的HTML文件
<html> <head><title>title</title></head> <body> <script> var old_valueOf = Array.prototype.valueOf; var old_toString = Array.prototype.toString; Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return old_valueOf.apply(this); }; Array.prototype.toString = function(){ console.log("Array::toString"); return old_toString.apply(this); }; console.log(1 == [1]); //Array::valueOf, Array::toString, true Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return 2; }; console.log(1 == [1]); //Array::valueOf, false Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return {}; }; Array.prototype.toString = function(){ console.log("Array::toString"); return {} }; console.log(1 == [1]); //Array::valueOf, Array::toString, Uncaught TypeError: Cannot convert object to primitive value </script> </body> </html>
这是由于正在进行比较的types。
在JavaScript中,可以使用==
或===
进行比较。 在三重平等的情况下,这就是所谓的平等无types强制 ,换句话说,这是一个严格的比较。
平等与types强制
相反,这意味着使用double等于操作数是与强制types相等的。
这是什么意思?
简而言之,这意味着JavaScript将使用内置方法来将值转换为原始types,以供比较。 具体来说,这些方法是.valueOf()
和.toString()
。
这里有些例子:
0 == false // true, auto type coercion 0 === false // false, because they are of a different type 1 == "1" // true, auto type coercion 1 === "1" // false, because they are of a different type
人机工程学:
1 == [1] // true 1 === [1] // false, because they are of a different type