这个问题的答案是社区的努力。编辑现有答案以改进这篇文章。它目前不接受新的答案或交互。
我正在使用 JSLint 浏览 JavaScript,并且在执行比较 if
内的 idSele_UNVEHtype.value.length == 0
之类的操作时,它返回了许多建议以将 ==
(两个等号)替换为 ===
(三个等号)陈述。
将 ==
替换为 ===
是否有性能优势?
由于存在许多比较运算符,因此欢迎任何性能改进。
如果不进行类型转换,是否会比 ==
获得性能提升?
严格相等运算符 (===
) 的行为与抽象相等运算符 (==
) 相同,只是不进行类型转换,并且类型必须相同才能被视为相等。
参考:Javascript Tutorial: Comparison Operators
==
运算符将在进行任何必要的类型转换后比较相等性。 ===
运算符将不进行转换,因此如果两个值的类型不同,===
将简单地返回 false
。两者都同样快。
引用 Douglas Crockford 的出色JavaScript: The Good Parts,
JavaScript 有两组相等运算符:=== 和 !==,以及它们的邪恶双胞胎 == 和 !=。好的工作按您期望的方式工作。如果两个操作数的类型相同且值相同,则 === 产生真,!== 产生假。当操作数是相同类型时,邪恶双胞胎会做正确的事情,但如果它们是不同类型,它们会尝试强制值。他们这样做的规则既复杂又难以忘怀。以下是一些有趣的案例: '' == '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
https://i.stack.imgur.com/yISob.png
缺乏传递性令人担忧。我的建议是永远不要使用邪恶的双胞胎。相反,请始终使用 === 和 !==。刚刚显示的所有比较都使用 === 运算符产生错误。
更新:
@Casebash 在评论和 @Phillipe Laybaert's 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
特殊情况是当您将一个原语与一个评估为相同原语的对象进行比较时,由于其 toString
或 valueOf
方法。例如,考虑将字符串原语与使用 String
构造函数创建的字符串对象进行比较。
"abc" == new String("abc") // true
"abc" === new String("abc") // false
这里 ==
运算符检查两个对象的值并返回 true
,但 ===
发现它们不是同一类型并返回 false
。哪一个是正确的?这实际上取决于您要比较的内容。我的建议是完全绕过这个问题,只是不要使用 String
构造函数从字符串文字创建字符串对象。
参考
http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3
使用 ==
运算符 (Equality)
true == 1; //true, because 'true' is converted to 1 and then compared
"2" == 2; //true, because "2" is converted to 2 and then compared
使用 ===
运算符 (Identity)
true === 1; //false
"2" === 2; //false
这是因为等式运算符 ==
确实类型强制,这意味着解释器会在比较之前隐式尝试转换值。
另一方面,身份运算符 ===
不进行类型强制,因此在比较时不转换值。
===
检查相等性和类型(称为 strict)。 Idendity 通常指的是“相同性”,由 Object.is
函数提供(根据 ES2015)。
这是 ==
和 ===
之间相等比较的有趣可视化。
来源:https://github.com/dorey/JavaScript-Equality-Table(demo、unified demo)
var1 === var2
使用 ===
进行 JavaScript 相等性测试时,一切都保持原样。
在评估之前没有任何内容被转换。
https://i.stack.imgur.com/62vxI.png
var1 == var2
使用 ==
进行 JavaScript 相等性测试时,会发生一些时髦的转换。
https://i.stack.imgur.com/35MpY.png
Javascript中的相等总结
https://i.stack.imgur.com/FX7z1.png
结论:
始终使用 ===
,除非您完全理解与 ==
发生的funky conversions。
==
不是传递的! (即使忽略 NaN
)
==
何时是非传递性的吗?
a = []
、b = false
和 c = [0]
。
在这里的答案中,我没有阅读任何关于 equal 含义的内容。有人会说 ===
表示相等且属于同一类型,但事实并非如此。这实际上意味着两个操作数都引用同一个对象,或者在值类型的情况下,具有相同的值。
因此,让我们采用以下代码:
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
类型的东西,大部分时间都表现为字符串。
让我补充一下这个忠告:
如有疑问,请阅读 specification!
ECMA-262 是一种脚本语言规范,JavaScript 是其方言。当然,在实践中,最重要的浏览器的行为方式比对应该如何处理某事的深奥定义更重要。但有助于理解为什么 new String("a") !== "a"。
请让我解释如何阅读规范以澄清这个问题。我看到在这个非常古老的话题中,没有人对非常奇怪的效果有答案。因此,如果您能阅读规范,这将对您的职业有极大的帮助。这是一种后天习得的技能。所以,让我们继续。
在 PDF 文件中搜索 === 会将我带到规范的第 56 页:11.9.4。严格的等于运算符( === ),在涉足规范之后,我发现:
11.9.6 严格等式比较算法 比较 x === y,其中 x 和 y 是值,产生真或假。这种比较的执行如下: 1. 如果 Type(x) 与 Type(y) 不同,则返回 false。 2. 如果 Type(x) 未定义,则返回 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. 返回错误。 11.如果Type(x)是String,那么如果x和y是完全相同的字符序列(长度相同,对应位置的字符相同),则返回true;否则,返回假。 12. 如果 Type(x) 是 Boolean,如果 x 和 y 都为真或都为假,则返回真;否则,返回假。 13. 如果 x 和 y 指代同一个对象或如果它们指代彼此连接的对象,则返回真(见 13.1.2)。否则,返回假。
有趣的是第 11 步。是的,字符串被视为值类型。但这并不能解释为什么 new String("a") !== "a"。我们是否有不符合 ECMA-262 的浏览器?
没那么快!
让我们检查操作数的类型。通过将它们包装在 typeof() 中自己尝试一下。我发现 new String("a") 是一个对象,使用第 1 步:如果类型不同则返回 false。
如果您想知道为什么 new String("a") 不返回字符串,那么来做一些阅读规范的练习怎么样?玩得开心!
Aidiakapi 在下面的评论中写道:
来自规范 11.2.2 The new Operator:如果 Type(constructor) 不是 Object,则抛出 TypeError 异常。换句话说,如果 String 不是 Object 类型,它就不能与 new 运算符一起使用。
new 总是返回一个 Object,即使对于 String 构造函数也是如此。唉!字符串的值语义(参见步骤 11)丢失。
这最终意味着:new String("a") !== "a"。
我在 Firefox 中使用 Firebug 使用如下代码对此进行了测试:
console.time("testEquality");变量 n = 0; while (true) { n++;如果(n == 100000)中断; } console.timeEnd("testEquality");
和
console.time("testTypeEquality");变量 n = 0; while (true) { n++;如果(n === 100000)中断; } console.timeEnd("testTypeEquality");
我的结果(每次测试五次并取平均值):
==: 115.2
===: 114.4
所以我想说微小的差异(这是超过 100000 次迭代,记住)可以忽略不计。性能不是做===
的理由。类型安全(好吧,就像你将在 JavaScript 中获得的一样安全),代码质量也是如此。
==
运算符存在实际类型强制时,它们如何比较?请记住,那是性能提升的时候。
在 PHP 和 JavaScript 中,它是一个严格的相等运算符。这意味着,它将比较类型和值。
在 JavaScript 中,它意味着相同的值和类型。
例如,
4 == "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**
这只是你用原语得到的疯狂的东西。
当您将 ==
与对象一起使用时,这是一个全新的疯狂水平。
在这一点上,您可能想知道...
为什么会这样?
嗯,这是因为与“三等号”(===
)不同,它只检查两个值是否相同。
==
做了一大堆其他事情。
它对函数有特殊处理,对空值、未定义、字符串有特殊处理,你可以命名它。
它变得很古怪。
实际上,如果您尝试编写一个执行 ==
的函数,它看起来像这样:
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();
}
那么这是什么意思?
这意味着 ==
很复杂。
因为它很复杂,所以很难知道使用它时会发生什么。
这意味着您最终可能会遇到错误。
所以这个故事的寓意是……
让你的生活不那么复杂。
使用 ===
而不是 ==
。
结束。
=== 运算符称为严格比较运算符,它确实不同于 == 运算符。
让我们取 2 个变量 a 和 b。
要使“a == b”评估为真,a 和 b 必须是相同的值。
在“a === b”的情况下,a 和 b 必须是相同的值和相同的类型才能评估为真。
举个例子
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,因此使用 === 运算符会更安全。
在 90% 的使用场景中,你使用哪一个并不重要,但是当你有一天遇到一些意想不到的行为时,很容易知道其中的区别。
=== 检查相同的边在类型和值上是否相等。
例子:
'1' === 1 // will return "false" because `string` is not a `number`
常见示例:
0 == '' // will be "true", but it's very common to want this check to be "false"
另一个常见的例子:
null == undefined // returns "true", but in most cases a distinction is necessary
很多时候,untyped 检查会很方便,因为您不在乎值是 undefined
、null
、0
还是 ""
严格相等/比较'==='的Javascript执行流程图
https://i.stack.imgur.com/A27Be.png
非严格相等/比较'=='的Javascript执行流程图
https://i.stack.imgur.com/Ccyb8.png
JavaScript ===
vs ==
.
0==false // true
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
这意味着没有类型强制的相等类型强制意味着 JavaScript 不会自动将任何其他数据类型转换为字符串数据类型
0==false // true,although they are different types
0===false // false,as they are different types
2=='2' //true,different types,one is string and another is integer but
javaScript convert 2 to string by using == operator
2==='2' //false because by using === operator ,javaScript do not convert
integer to string
2===2 //true because both have same value and same types
在典型的脚本中不会有性能差异。更重要的可能是千“===”比千“==”重 1 KB :) JavaScript profilers 可以告诉您在您的情况下是否存在性能差异。
但就我个人而言,我会按照 JSLint 的建议去做。这个建议不是因为性能问题,而是因为类型强制意味着 ('\t\r\n' == 0)
为真。
相等比较运算符 == 令人困惑,应避免使用。
如果您必须忍受它,请记住以下三件事:
它不是传递性的:(a == b) 和 (b == c) 不会导致 (a == c) 它的否定是互斥的:(a == b) 和 (a != b) 总是成立相反的布尔值,所有 a 和 b。如有疑问,请记住以下真值表:
JAVASCRIPT 中的相等运算符真值表
表中的每一行都是一组 3 个相互“相等”的值,这意味着它们中的任何 2 个值都使用等号 == 符号*
**奇怪:请注意,第一列上的任何两个值在这个意义上都不相等。**
'' == 0 == false // Any two values among these 3 ones are equal with the == operator
'0' == 0 == false // Also a set of 3 equal values, note that only 0 and false are repeated
'\t' == 0 == false // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
'\r' == 0 == false // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
'\n' == 0 == false // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
'\t\r\n' == 0 == false // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
null == undefined // These two "default" values are not-equal to any of the listed values above
NaN // NaN is not equal to any thing, even to itself.
在您的使用中,这两个操作之间不太可能有任何性能差异。无需进行类型转换,因为两个参数已经是相同的类型。这两个操作都有一个类型比较,然后是一个值比较。
是的!这很重要。
javascript 中的 ===
运算符检查值和类型,其中 ==
运算符只检查 值(如果需要,进行类型转换)。
https://i.stack.imgur.com/5ttlR.png
您可以轻松地对其进行测试。将以下代码粘贴到 HTML 文件中并在浏览器中打开
<script>
function onPageLoad()
{
var x = "5";
var y = 5;
alert(x === 5);
};
</script>
</head>
<body onload='onPageLoad();'>
您将在警报中收到“false”。现在将 onPageLoad()
方法修改为 alert(x == 5);
,您将得到 true。
简单地
==
表示操作数之间的比较具有类型强制
和
===
表示操作数之间的比较没有类型强制。
JavaScript 中的类型强制意味着自动将数据类型转换为其他数据类型。
例如:
123 == "123" // Returns true, because JS coerces string "123" to number 123
// and then goes on to compare `123 == 123`.
123 === "123" // Returns false, because JS does not coerce values of different types here.
根据经验,我通常会使用 ===
而不是 ==
(以及 !==
而不是 !=
)。
上面的答案中解释了原因,Douglas Crockford 也很清楚(JavaScript: The Good Parts)。
但是有一个例外:== null
是检查“为空或未定义”的有效方法:
if( value == null ){
// value is either null or undefined
}
例如 jQuery 1.9.1 使用这种模式 43 次,并且 JSHint syntax checker 甚至为此提供了 eqnull
放松选项。
应该使用严格的相等检查 (===) 来支持 ==。唯一的例外是在通过 null 检查未定义和 null 时。
// Check for both undefined and null values, for some important reason.
undefOrNull == null;
编辑 2021-03:
现在 most browsers 支持 Nullish coalescing operator (??
) 和 Logical nullish assignment (??=)
,如果变量为 null 或未定义,则可以更简洁地分配默认值,例如:
if (a.speed == null) {
// Set default if null or undefined
a.speed = 42;
}
可以写成这些形式中的任何一种
a.speed ??= 42;
a.speed ?? a.speed = 42;
a.speed = a.speed ?? 42;
这是一个严格的检查测试。
这是一件好事,尤其是当您在 0 和 false 和 null 之间进行检查时。
例如,如果您有:
$a = 0;
然后:
$a==0;
$a==NULL;
$a==false;
全部返回 true,您可能不希望这样。假设您有一个函数可以返回数组的第 0 个索引或在失败时返回 false。如果你用“==”检查,你会得到一个令人困惑的结果。
所以和上面一样,但是经过严格的测试:
$a = 0;
$a===0; // returns true
$a===NULL; // returns false
$a===false; // returns false
0 != null
。 -1
===
运算符检查变量的值和类型是否相等。
==
运算符仅检查变量的值是否相等。
JSLint 有时会给你不切实际的理由来修改东西。如果类型已经相同,===
的性能与 ==
完全相同。
只有当类型不同时它才会更快,在这种情况下它不会尝试转换类型而是直接返回false。
因此,恕我直言,JSLint 可能用于编写新代码,但应不惜一切代价避免无用的过度优化。
这意味着,当您知道 a 只能是字符串这一事实时,没有理由在像 if (a == 'test')
这样的检查中将 ==
更改为 ===
。
以这种方式修改大量代码会浪费开发人员和审阅者的时间,而且一无所获。
a.length===4
在 Firefox 中实际上比 a.length==4
慢。无论如何,这无论如何都是一种微优化,但这与人们声称的相反。
一个简单的例子是
2 == '2' -> true, values are SAME because of type conversion.
2 === '2' -> false, values are NOT SAME because of no type conversion.
前 2 个答案都提到 == 表示平等, === 表示身份。不幸的是,这种说法是不正确的。
如果 == 的两个操作数都是对象,则比较它们是否是同一个对象。如果两个操作数都指向同一个对象,则等号运算符返回 true。否则,两者不相等。
var a = [1, 2, 3];
var b = [1, 2, 3];
console.log(a == b) // false
console.log(a === b) // false
在上面的代码中,== 和 === 都为 false,因为 a 和 b 不是同一个对象。
也就是说:如果 == 的两个操作数都是对象,那么 == 的行为与 === 相同,这也意味着身份。这两个运算符的本质区别在于类型转换。 == 在检查相等性之前进行了转换,但 === 没有。
问题是你可能很容易遇到麻烦,因为 JavaScript 有很多隐式转换意味着......
var x = 0;
var isTrue = x == null;
var isFalse = x === null;
这很快就会成为一个问题。可以从 MFC / C++ 中的这段代码中获取为什么隐式转换是“邪恶”的最佳示例,由于从 CString 到 HANDLE 的隐式转换,它实际上将编译,这是一个指针 typedef 类型......
CString x;
delete x;
这显然在运行时做了非常未定义的事情......
谷歌在 C++ 和 STL 中进行隐式转换以获得一些反对它的论点......
0 == null
为假。
平等比较:
运算符 ==
当两个操作数相等时返回真。在比较之前,操作数被转换为相同的类型。
>>> 1 == 1
true
>>> 1 == 2
false
>>> 1 == '1'
true
相等和类型比较:
运算符 ===
如果两个操作数相等且类型相同,则返回 true。如果以这种方式进行比较,通常会更好、更安全,因为没有幕后的类型转换。
>>> 1 === '1'
false
>>> 1 === 1
true
这是一个方便的比较表,其中显示了发生的转化以及 ==
和 ===
之间的差异。
正如结论所说:
“除非您完全理解二等式的转换,否则请使用三等式。”
http://dorey.github.io/JavaScript-Equality-Table/
null 和 undefined 是虚无,也就是说,
var a;
var b = null;
这里 a
和 b
没有值。而 0、false 和 '' 都是值。所有这些的共同点是它们都是虚假值,这意味着它们都满足虚假条件。
所以,0、false 和 '' 一起构成了一个子组。另一方面, null & undefined 形成第二个子组。检查下图中的比较。 null 和 undefined 将相等。其他三个将彼此相等。但是,它们在 JavaScript 中都被视为虚假条件。
https://i.stack.imgur.com/11I0i.jpg
这与任何对象(如 {}、数组等)相同,非空字符串和布尔值 true 都是真值条件。但是,它们都不是平等的。
-0
?(-0).toString()
as"0"
,但并非所有语言都这样做(例如,在 C# 中,Math.Round(-0.1).ToString()
是"-0"
)。这可能会导致像x == 0 ? 0 : x
这样的奇怪修复。