在 JavaScript 比较中应该使用哪个等号运算符(== vs ===)?

Posted

技术标签:

【中文标题】在 JavaScript 比较中应该使用哪个等号运算符(== vs ===)?【英文标题】:Which equals operator (== vs ===) should be used in JavaScript comparisons? 【发布时间】:2010-09-26 10:43:47 【问题描述】:

我正在使用 JSLint 浏览 javascript,并且在执行比较 idSele_UNVEHtype.value.length == 0if 声明。

=== 替换== 是否有性能优势?

由于存在许多比较运算符,因此欢迎任何性能改进。

如果不进行类型转换,是否会比== 获得性能提升?

【问题讨论】:

【参考方案1】:

严格相等运算符 (===) 的行为与抽象相等运算符 (==) 相同,只是不进行类型转换,并且类型必须相同才能被视为相等。

参考:Javascript Tutorial: Comparison Operators

== 运算符将在进行任何必要的类型转换后比较是否相等=== 运算符将进行转换,因此如果两个值的类型不同,=== 将简单地返回 false。两者都一样快。

引用道格拉斯·克罗克福德的优秀JavaScript: The Good Parts,

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 在 cmets 和 @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

特殊情况是当您将一个原语与一个评估为相同原语的对象进行比较时,由于其toStringvalueOf 方法。例如,考虑将字符串原语与使用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

【讨论】:

我还要指出 0 === -0 和 NaN !== NaN,这有时会令人困惑。如果要区分 ±0 并认为 NaN 相等,请使用 Object.is (ES2015) 软打字是一个功能。显然 Crockford 指出了设计决策的一些“人工制品”,但软打字仍然是一个特性。如果使用得当,使用起来绝对没问题。不要把婴儿和洗澡水一起扔掉。 你为什么需要使用-0 我有很多工作【参考方案2】:

使用== 运算符(平等

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

这是因为等式运算符== 确实类型强制,这意味着解释器会在比较之前隐式尝试转换值。

另一方面,身份运算符=== 不进行类型强制,因此在比较时不会转换值,因此速度更快(根据This JS benchmark 测试)因为它跳过了一步。

【讨论】:

【参考方案3】:

这是===== 之间相等比较的有趣可视化。

来源:https://github.com/dorey/JavaScript-Equality-Table(demo,unified demo)


var1 === var2

当使用=== 进行 JavaScript 相等性测试时,一切都保持原样。 在评估之前没有任何东西被转换。

var1 == var2

当使用 == 进行 JavaScript 相等性测试时,会发生一些时髦的转换

Javascript 中的相等性总结


结论:

除非您完全理解与== 发生的funky conversions,否则请始终使用===

【讨论】:

更好的 '==' 表:algassert.com/visualization/2014/03/27/… 至少 == 比较是可交换的(即 (a==b) === (b==a))XD【参考方案4】:

在此处的答案中,我没有阅读任何关于 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

这种行为并不总是很明显。这个故事不仅仅是平等和同一类型。

规则是:

对于值类型(数字):如果 ab 具有相同的值并且属于相同的类型,则a === b 返回 true

对于引用类型:如果 ab 引用完全相同的对象,则a === b 返回 true

对于字符串:如果ab 都是字符串并且包含完全相同的字符,则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 不是同一类型。 aObject 类型,而 bstring 类型。请记住,使用String 构造函数创建字符串对象会创建Object 类型的东西,大部分时间都表现为字符串。

【讨论】:

【参考方案5】:

让我补充一下这个忠告:

如有疑问,请阅读specification!

ECMA-262 是一种脚本语言规范,JavaScript 是其方言。当然,在实践中,最重要的浏览器的行为方式比对应该如何处理某事的深奥定义更重要。但是了解为什么 new String("a") !== "a" 会很有帮助。

请让我解释一下如何阅读规范以澄清这个问题。我看到在这个非常古老的话题中,没有人对非常奇怪的效果有答案。因此,如果您能阅读规范,这将对您的职业有极大的帮助。这是一种后天习得的技能。那么,让我们继续吧。

在 PDF 文件中搜索 === 会将我带到规范的第 56 页:11.9.4。严格等号运算符 ( === ),在涉足规范之后,我发现:

11.9.6 严格等式比较算法 比较 x === y,其中 x 和 y 是值,产生 truefalse。如下进行这样的比较: 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 指代同一个对象或如果它们指代彼此连接的对象,则返回 true(参见 13.1.2)。否则,返回 false

有趣的是第 11 步。是的,字符串被视为值类型。但这并不能解释为什么 new String("a") !== "a"。我们是否有不符合 ECMA-262 的浏览器?

没那么快!

让我们检查操作数的类型。将它们包装在 typeof() 中,自己尝试一下。我发现new String("a")是一个对象,使用第1步:如果类型不同则返回false

如果您想知道为什么 new String("a") 不返回字符串,那么来做一些阅读规范的练习怎么样?玩得开心!


Aidiakapi 在下面的评论中写道:

来自规范

11.2.2 新运营商

如果 Type(constructor) 不是 Object,则抛出 TypeError 异常。

换句话说,如果 String 不是 Object 类型,它就不能与 new 运算符一起使用。

new 总是返回一个 Object,即使对于 String 构造函数也是如此。唉!字符串的值语义(参见步骤 11)丢失。

这最终意味着:new String("a") !== "a"

【讨论】:

【参考方案6】:

我在 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 中一样安全)和代码质量。

【讨论】:

现在,当== 运算符存在实际类型强制时,它们如何比较?请记住,这就是性能提升的时候。 正确测试时的主要区别在于上述原因更快地只检查类型不等式。 jsfiddle.net/4jhuxkb2【参考方案7】:

php 和 JavaScript 中,它是一个严格的相等运算符。这意味着,它将比较类型和值。

【讨论】:

【参考方案8】:

在 JavaScript 中,它表示相同的值和类型。

例如,

4 == "4" // will return true

但是

4 === "4" // will return false 

【讨论】:

【参考方案9】:

为什么== 如此难以预测?

将空字符串 "" 与数字零 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();

那么这是什么意思?

表示==很复杂。

因为它很复杂,所以当你使用它时很难知道会发生什么。

这意味着您最终可能会遇到错误。

所以这个故事的寓意是……

让你的生活不那么复杂。

使用=== 代替==

结局。

【讨论】:

【参考方案10】:

=== 运算符称为严格比较运算符,它确实不同于 == 运算符。

让我们取 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% 的使用场景中,您使用哪一种并不重要,但是当您有一天遇到一些意外行为时,了解其中的区别会很方便。

【讨论】:

【参考方案11】:

=== 检查相同边在 typevalue 中是否相等。


示例:

'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

很多时候,无类型检查会很方便,因为您不在乎值是undefinednull0 还是""

【讨论】:

【参考方案12】:

严格相等/比较'==='的Javascript执行流程图

非严格相等/比较'=='的Javascript执行流程图

【讨论】:

【参考方案13】:

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

【讨论】:

【参考方案14】:

这意味着没有类型强制的平等 类型强制意味着 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 

【讨论】:

【参考方案15】:

在典型的脚本中不会有性能差异。更重要的可能是千个“===”比千个“==”重 1 KB :)JavaScript profilers 可以告诉您在您的情况下是否存在性能差异。

但我个人会按照 JSLint 的建议去做。这个建议不是因为性能问题,而是因为类型强制意味着('\t\r\n' == 0) 为真。

【讨论】:

【参考方案16】:

相等比较运算符 == 容易混淆,应避免使用。

如果您必须忍受它,请记住以下 3 件事:

    不可传递:(a == b)(b == c) 不会导致 (a == c ) 它的否定是互斥的:(a == b)(a != b) 总是持有相反的布尔值,所有 a 和b. 如有疑问,请牢记以下真值表:

JAVASCRIPT 中的相等运算符真值表

表中的每一行都是一组 3 个相互“相等”的值,这意味着它们中的任何 2 个值都使用等号 == 符号*

** STRANGE:请注意,第一列上的任何两个值在这个意义上都不相等。**

''       == 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.

【讨论】:

【参考方案17】:

在您的使用中,这两个操作之间不太可能存在任何性能差异。无需进行类型转换,因为两个参数已经是相同的类型。这两个操作都有一个类型比较,然后是一个值比较。

【讨论】:

【参考方案18】:

是的!这很重要。

=== javascript 中的运算符检查值和类型,而== 运算符只检查值(如果需要,进行类型转换)

您可以轻松地对其进行测试。将以下代码粘贴到 html 文件中并在浏览器中打开

<script>

function onPageLoad()

    var x = "5";
    var y = 5;
    alert(x === 5);
;

</script>

</head>

<body onload='onPageLoad();'>

您将在警报中收到“false”。现在将onPageLoad() 方法修改为alert(x == 5); 你会得到true

【讨论】:

【参考方案19】:

简单

== 表示操作数之间的比较具有类型强制

=== 表示操作数之间的比较没有类型强制。

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.

【讨论】:

【参考方案20】:

这是一个严格的检查测试。

这是一件好事,尤其是当您在 0 和 false 和 null 之间进行检查时。

例如,如果您有:

$a = 0;

然后:

$a==0; 
$a==NULL;
$a==false;

All 返回 true,您可能不希望这样。假设您有一个函数可以返回数组的第 0 个索引或在失败时返回 false。如果你用 "==" false 检查,你会得到一个令人困惑的结果。

所以和上面一样,但是要严格测试:

$a = 0;

$a===0; // returns true
$a===NULL; // returns false
$a===false; // returns false

【讨论】:

在 JavaScript 中,这是完全错误的,错误的不完整。 0 != null。 -1【参考方案21】:

=== 运算符检查变量的值和类型是否相等。

== 运算符只是检查变量的值是否相等。

【讨论】:

【参考方案22】:

JSLint 有时会给你不切实际的理由来修改东西。如果类型已经相同,=== 的性能与 == 完全相同。

只有在类型不相同的情况下才会更快,这种情况下不会尝试转换类型而是直接返回false。

所以,恕我直言, JSLint 可能用于编写新代码,但应不惜一切代价避免无用的过度优化。

意思是,当您知道 a 只能是字符串这一事实时,没有理由在像 if (a == 'test') 这样的检查中将 == 更改为 ===

以这种方式修改大量代码会浪费开发人员和审阅者的时间,而且一无所获。

【讨论】:

有趣的是,a.length===4 在 Firefox 中实际上比a.length==4。无论如何,这无论如何都是一种微优化,但这与人们声称的相反。【参考方案23】:

根据经验,我通常会使用=== 而不是==(以及!== 而不是!=)。

上面的答案中解释了原因,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 放松选项。

来自jQuery style guide:

应该使用严格的相等检查 (===) 来支持 ==。唯一的 例外是通过 null 检查 undefined 和 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;

【讨论】:

== null 是检查‘是null 还是undefined’的有效方法” ... or document.all【参考方案24】:

一个简单的例子是

2 == '2'  -> true, values are SAME because of type conversion.

2 === '2'  -> false, values are NOT SAME because of no type conversion.

【讨论】:

【参考方案25】:

提到的前 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 不是同一个对象。

也就是说:如果 == 的两个操作数都是对象,则 == 的行为与 === 相同,这也意味着身份。这两个运算符的本质区别在于类型转换。 == 在检查相等性之前进行了转换,但 === 没有。

【讨论】:

【参考方案26】:

问题是你可能很容易遇到麻烦,因为 JavaScript 有很多隐式转换的含义......

var x = 0;
var isTrue = x == null;
var isFalse = x === null;

这很快就会成为一个问题。为什么隐式转换是“邪恶”的最佳示例可以从MFC/C++ 中的这段代码中获取,由于从 CString 到 HANDLE 的隐式转换,它实际上会编译,这是一个指针 typedef 类型......

CString x;
delete x;

很明显,在运行时非常未定义的事情......

Google 在 C++ 和 STL 中进行隐式转换以获得一些反对它的论据...

【讨论】:

0 == null 为假。【参考方案27】:

来自core javascript reference

=== 如果操作数严格相等,则返回true(见上文) 没有类型转换。

【讨论】:

【参考方案28】:

平等比较:

接线员==

当两个操作数相等时返回真。操作数在进行比较之前转换为相同的类型。

>>> 1 == 1
true
>>> 1 == 2
false
>>> 1 == '1'
true

等式和类型比较:

接线员===

如果两个操作数相等且类型相同,则返回 true。一般是这样 如果您比较这种方式会更好、更安全,因为没有幕后的类型转换。

>>> 1 === '1'
false
>>> 1 === 1
true

【讨论】:

【参考方案29】:

这是一个方便的比较表,显示了发生的转换以及===== 之间的差异。

正如结论所说:

“除非您完全理解所需的转换,否则请使用三个等于 两个等于的地方。”

http://dorey.github.io/JavaScript-Equality-Table/

【讨论】:

【参考方案30】:

null和undefined都是虚无,也就是

var a;
var b = null;

这里ab 没有值。而 0、false 和 '' 都是值。所有这些的共同点是它们都是虚假值,这意味着它们都满足虚假条件。

所以,0、false 和 '' 一起构成了一个子组。另一方面, null & undefined 形成第二个子组。检查下图中的比较。 null 和 undefined 将相等。其他三个将彼此相等。但是,它们在 JavaScript 中都被视为虚假条件。

这与任何对象(如 、数组等)相同,非空字符串和布尔值 true 都是真值条件。但是,它们并不相等。

【讨论】:

以上是关于在 JavaScript 比较中应该使用哪个等号运算符(== vs ===)?的主要内容,如果未能解决你的问题,请参考以下文章

在 JavaScript 比较中应该使用哪个等号运算符(== vs ===)?

在 JavaScript 比较中应该使用哪个等号运算符(== vs ===)?

在 JavaScript 比较中应该使用哪个等号运算符(== vs ===)?

在 JavaScript 比较中应该使用哪个等号运算符(== vs ===)?

我可以使用三等号进行 JavaScript 字符串比较吗?

javascript基础:等号比较