我使用JSLint检查JavaScript代码,它建议将比较语句中的==
(两个等号)替换为===
(三个等号),例如在if
语句中比较idSele_UNVEHtype.value.length == 0
。
使用===
代替==
是否有性能优势?
任何性能提升都是受欢迎的,因为存在许多比较运算符。
如果不涉及类型转换,是否会比使用==
更快?
我使用JSLint检查JavaScript代码,它建议将比较语句中的==
(两个等号)替换为===
(三个等号),例如在if
语句中比较idSele_UNVEHtype.value.length == 0
。
使用===
代替==
是否有性能优势?
任何性能提升都是受欢迎的,因为存在许多比较运算符。
如果不涉及类型转换,是否会比使用==
更快?
===
)与抽象相等运算符(==
)的行为完全相同,除了不进行类型转换,并且必须具有相同的类型才能被视为相等。==
运算符将在执行任何必要的类型转换后进行比较。 ===
运算符将不会进行转换,因此如果两个值不是相同类型,则 ===
将简单地返回 false
。两者都同样快。JavaScript 有两组相等运算符:
===
和!==
,以及它们的邪恶孪生兄弟==
和!=
。好的运算符按照你的预期工作。如果两个操作数具有相同的类型并且具有相同的值,则===
生成true
,!==
生成false
。当操作数具有相同类型时,邪恶孪生兄弟也会做正确的事情,但是如果它们具有不同的类型,则会尝试强制转换值。它们执行此操作的规则是复杂而难以记忆的。以下是一些有趣的情况:
'' == '0' // false 0 == '' // true 0 == '0' // true
false == 'false' // false
false == '0' // true
false == undefined // false false == null // false null == undefined // true
缺乏传递性是令人担忧的。我的建议是永远不要使用邪恶的双胞胎。相反,总是使用' \t\r\n ' == 0 // true
===
和!==
。所有刚才展示的比较都使用 ===
运算符产生 false
。
@Casebash在评论和@Phillipe Laybaert的answer中提出了一个很好的观点,涉及对象。对于对象,==
和===
之间始终一致(特殊情况除外)。
var a = [1,2,3];
var b = [1,2,3];
var c = { x: 1, y: 2 };
var d = { x: 1, y: 2 };
var e = "text";
var f = "te" + "xt";
a == b // false
a === b // false
c == d // false
c === d // false
e == f // true
e === f // true
"abc" == new String("abc") // true
"abc" === new String("abc") // false
这里的==
运算符检查两个对象的值并返回true
,但===
发现它们不是相同类型并返回false
。哪一个是正确的?这取决于你想要比较什么。我的建议是完全绕过这个问题,不要使用String
构造函数从字符串字面量创建字符串对象。
Reference
https://262.ecma-international.org/5.1/#sec-11.9.3
==
运算符(相等性)true == 1; //true, because 'true' is converted to 1 and then compared
"2" == 2; //true, because "2" is converted to 2 and then compared
===
运算符 (恒等性判断)true === 1; //false
"2" === 2; //false
==操作符会进行类型转换,这意味着解释器在比较值之前会尝试隐式地将它们转换为相同类型。
另一方面,===操作符不会进行类型转换,在比较时不会将值转换为相同类型。
===
用于检查相等性和类型(称为“严格”比较)。通常,“身份(identity)”指的是“相同性(sameness)”,可以通过ES2015中的Object.is
函数来实现。 - BanksySan这里有一份关于 ==
和 ===
相等性比较的有趣可视化。
来源: https://github.com/dorey/JavaScript-Equality-Table (演示, 统一演示)
var1 === var2
在 JavaScript 中使用 ===
进行相等性测试时,一切都是原样的。
在进行求值之前不会进行任何转换。
var1 == var2
在 JavaScript 中使用 ==
进行相等性测试时,会发生一些奇怪的转换。
始终使用 ===
,除非您完全理解 ==
中发生的奇怪转换(funky conversions)。
==
不是传递的例子吗? - SNaga = []
,b = false
和c = [0]
。 - Feuermurmel==
比较值类型的值和引用类型的引用(同一实例)。这很好而且有用(能够比较引用通常是有帮助的)。但当==
强制转换引用类型进行比较时,它就会变得混乱不堪,隐式地将它们视为值类型。 - Feuermurmel===
表示相等且类型相同,但这并不是真的。它实际上意味着两个操作数引用相同的对象,或者在值类型的情况下具有相同的值。那么,让我们看一下以下代码:
var a = [1,2,3];
var b = [1,2,3];
var c = a;
var ab_eq = (a === b); // false (even though a and b are the same type)
var ac_eq = (a === c); // true
同样的情况也发生在这里:
var a = { x: 1, y: 2 };
var b = { x: 1, y: 2 };
var c = a;
var ab_eq = (a === b); // false (even though a and b are the same type)
var ac_eq = (a === c); // true
或者甚至:
var a = { };
var b = { };
var c = a;
var ab_eq = (a === b); // false (even though a and b are the same type)
var ac_eq = (a === c); // true
这种行为并不总是显而易见。与相等和类型相同还有更多的故事。
规则如下:
对于值类型(数字):
a === b
如果 a
和 b
具有相同的值且类型相同,则返回 true
对于引用类型:
a === b
如果 a
和 b
引用完全相同的对象,则返回 true
对于字符串:
a === b
如果 a
和 b
都是字符串且包含完全相同的字符,则返回 true
字符串不是值类型,但在Javascript中它们的行为类似于值类型,所以当字符串中的字符相同时且长度相同时(如第三条规则所述),它们将是“相等”的。
现在变得有趣了:
var a = "12" + "3";
var b = "123";
alert(a === b); // returns true, because strings behave like value types
不过这个怎么办呢?:
var a = new String("123");
var b = "123";
alert(a === b); // returns false !! (but they are equal and of the same type)
我以为字符串像值类型一样?好吧,这要看你问谁了... 在这种情况下,a
和 b
不是相同的类型。a
是一个 Object
类型,而 b
是一个 string
类型。只需记住,使用 String
构造函数创建字符串对象会创建一个行为大多数情况下像字符串的 Object
。
有趣的是第11步。是的,字符串被视为值类型。但这并不能解释为什么“new String(“a”)!==“a””。我们有没有一个不符合ECMA-262标准的浏览器?11.9.6严格相等比较算法
比较x === y,其中x和y是值,产生true或false。这样的比较按如下方式执行:
1.如果Type(x)与Type(y)不同,则返回false。
2.如果Type(x)是Undefined,则返回true。
3.如果Type(x)为Null,则返回true。
4.如果Type(x)不是Number,则转到步骤11。
5.如果x是NaN,则返回false。
6.如果y是NaN,则返回false。
7.如果x和y是相同的数字值,则返回true。
8.如果x是+0,y是-0,则返回true。
9.如果x是-0,y是+0,则返回true。
10.返回false。
11.如果Type(x)是String,则如果x和y是完全相同的字符序列(长度相同且对应位置上的字符相同),则返回true;否则,返回false。
12.如果Type(x)是Boolean,则如果x和y都是true或都是false,则返回true;否则,返回false。
13.如果x和y引用同一个对象,或者它们引用相互连接的对象(参见13.1.2),则返回true。否则,返回false。
我使用类似下面的代码在Firefox浏览器中通过Firebug进行了测试:
console.time("testEquality");
var n = 0;
while (true) {
n++;
if (n == 100000)
break;
}
console.timeEnd("testEquality");
并且
console.time("testTypeEquality");
var n = 0;
while (true) {
n++;
if (n === 100000)
break;
}
console.timeEnd("testTypeEquality");
我的结果(每个测试都进行了五次并进行了平均):
==: 115.2
===: 114.4
所以我会说微小的差异(请记住这是超过100000个迭代)可以被忽略。性能不是使用 ===
的理由。类型安全(尽管只能在JavaScript中保证相对的安全)和代码质量才是。
==
运算符的类型强制转换时,它们是如何进行比较的呢?记住,这时会有性能提升。 - Hubert OG4 == "4" // will return true
但是
4 === "4" // will return false
为什么==
是如此不可预测的?
当你将空字符串""
与数字零0
进行比较时,会得到什么?
true
没错,按照==
的说法,空字符串和数字零是相同的。
而且问题并不止于此,以下是另一个例子:
'0' == false // true
数组会让事情变得非常奇怪。
[1] == true // true
[] == false // true
[[]] == false // true
[0] == false // true
然后与字符串更奇怪
[1,2,3] == '1,2,3' // true - REALLY?!
'\r\n\t' == 0 // true - Come on!
情况还会变得更糟:
什么时候等于不等于?
let A = '' // empty string
let B = 0 // zero
let C = '0' // zero string
A == B // true - ok...
B == C // true - so far so good...
A == C // **FALSE** - Plot twist!
让我再说一遍:
(A == B) && (B == C) // true
(A == C) // **FALSE**
这只是原始类型的疯狂表现。
当你使用==
与对象一起使用时,它会变得更加疯狂。
此时您可能会想...
为什么会这样呢?
这是因为与“三个等号”(===
)不同,==
执行许多其他操作。
它对函数有特殊处理,对null、undefined、字符串等也有特殊处理。
它变得非常疯狂。
实际上,如果您尝试编写一个执行==
操作的函数,它看起来会像这样:
function isEqual(x, y) { // if `==` were a function
if(typeof y === typeof x) return y === x;
// treat null and undefined the same
var xIsNothing = (y === undefined) || (y === null);
var yIsNothing = (x === undefined) || (x === null);
if(xIsNothing || yIsNothing) return (xIsNothing && yIsNothing);
if(typeof y === "function" || typeof x === "function") {
// if either value is a string
// convert the function into a string and compare
if(typeof x === "string") {
return x === y.toString();
} else if(typeof y === "string") {
return x.toString() === y;
}
return false;
}
if(typeof x === "object") x = toPrimitive(x);
if(typeof y === "object") y = toPrimitive(y);
if(typeof y === typeof x) return y === x;
// convert x and y into numbers if they are not already use the "+" trick
if(typeof x !== "number") x = +x;
if(typeof y !== "number") y = +y;
// actually the real `==` is even more complicated than this, especially in ES6
return x === y;
}
function toPrimitive(obj) {
var value = obj.valueOf();
if(obj !== value) return value;
return obj.toString();
}
那么这意味着什么?
这意味着==
是很复杂的。
因为它很复杂,所以当你使用它时很难知道会发生什么。
这意味着你可能会遇到错误。
所以故事的寓意是...
让你的生活不那么复杂。
使用===
代替==
。
结尾。
var a = 1;
var b = "1";
if (a == b) //evaluates to true as a and b are both 1
{
alert("a == b");
}
if (a === b) //evaluates to false as a is not the same type as b
{
alert("a === b");
}
总之,使用==运算符可能会在您不希望的情况下评估为true,因此使用===运算符会更安全。
(-0).toString()
定义为"0"
,但并不是每种编程语言都是这样(例如在 C# 中,Math.Round(-0.1).ToString()
是"-0"
)。这可能会导致奇怪的修复方式,如x == 0 ? 0 : x
。 - Cole Tobin(-0).toString()
中,你确定(-0)
会创建一个负零吗?(可能与符号字符是否是Javascript字面量语法语法的一部分有关,或者像许多其他语言一样,-0
是应用于仅由数字组成的文字的一元否定) - Ben Voigt(-0)
是对仅由数字组成的文字面量应用一元减运算符:https://tc39.es/ecma262/#sec-literals-numeric-literals 但尽管如此,它确实形成负零。 - Ben Voigt