博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Javascript 中 == 和 === 区别是什么?
阅读量:4320 次
发布时间:2019-06-06

本文共 8637 字,大约阅读时间需要 28 分钟。

Javascript 中 == 和 === 区别是什么?

 

 

作者:Belleve
链接:https://www.zhihu.com/question/31442029/answer/77772323
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
谁告诉你 == 不会有副作用的
var x = 1; var obj = { valueOf: function(){ x = 2; return 0 }} console.log(obj == 0, x) // true, 2
甚至还会产生异常呢
var x = 1; var obj = { valueOf: function(){ return {} }, toString: function(){ return {}}} console.log(obj == 0) // Error: Cannot convert object to primitive value
————————————————————————————————————————————
这是 ==<img src="https://pic1.zhimg.com/50/41b28b0c6def1909e0ad1da86093e620_hd.png" data-rawwidth="1424" data-rawheight="1417" class="origin_image zh-lightbox-thumb" width="1424" data-original="https://pic1.zhimg.com/41b28b0c6def1909e0ad1da86093e620_r.png">
这是 ===<img src="https://pic4.zhimg.com/50/eb4c38443744d02015ddbe9bfd775eb3_hd.png" data-rawwidth="1415" data-rawheight="1410" class="origin_image zh-lightbox-thumb" width="1415" data-original="https://pic4.zhimg.com/eb4c38443744d02015ddbe9bfd775eb3_r.png">
完整比较图:
  • 红色:===
  • 橙色:==
  • 黄色:<= 和 >= 同时成立,== 不成立
  • 蓝色:只有 >=
  • 绿色:只有 <=

 

&amp;amp;amp;amp;lt;img src="https://pic3.zhimg.com/50/b922270259dece707ef6c6a50259a406_hd.png" data-rawwidth="1420" data-rawheight="1418" class="origin_image zh-lightbox-thumb" width="1420" data-original="https://pic3.zhimg.com/b922270259dece707ef6c6a50259a406_r.png"&amp;amp;amp;amp;gt;
(参: , )

 

顺便,有人说这图像现代艺术,感觉旋转完更像,删减重排换成 S1 配色之后做成头像了。
不免费帮人做头像(也就是换个顺序的事情)
&amp;amp;amp;amp;lt;img src="https://pic3.zhimg.com/50/27a6f55c41ace25f058625b3073ad492_hd.png" data-rawwidth="1600" data-rawheight="1600" class="origin_image zh-lightbox-thumb" width="1600" data-original="https://pic3.zhimg.com/27a6f55c41ace25f058625b3073ad492_r.png"&amp;amp;amp;amp;gt;

 

 

 

作者:林建入
链接:https://www.zhihu.com/question/20348948/answer/19601270
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
很多时候我们会对某个语言的某个特性争论不休,通常都只是因为我们不知道它是怎么实现的。其实解决这个疑惑的最好的方法,就是弄清楚 == 和 === 内部的实现机制。
例如 Google v8 就是开源的,只要看看里面的代码,就能知道到底是怎么一回事了。但是我相信绝大多数人都是没有这个耐心的——我知道大家都在忙着挣钱养家——好吧,那咱就不看 Google v8 了,看看 ECMA-262 吧,里面已经把实现算法描述得很清楚了,只要看懂了下面的内容,以后就再也不会有此类疑问了。
 
 
一、严格相等运算符 === 的实现
=== 被称为 Strict Equals Operator,假设有表达式 a === b,则它的实际运算过程如下
  1. 计算出表达式 a 的结果,并存入 lref 变量
  2. 将 GetValue(lref) 的结果存入 lval 变量
  3. 计算出表达式 b 的结果,并存入 rref 变量
  4. 将 GetValue(rref) 的结果存入 rval 变量
  5. 执行 Strict Equality Comparison 算法判断 rval === lval 并将结果直接返回
这里的
Strict Equality Comparison 算法很关键,假设要计算的是 x === y,则过程如下

1. 如果 Type(x) 和 Type(y) 不同,返回 false

2. 如果 Type(x) 为 Undefined,返回 true

3. 如果 Type(x) 为 Null,返回 true

4. 如果 Type(x) 为 Number,则进入下面的判断逻辑

4.1. 如果 x 为 NaN,返回 false

4.2. 如果 y 为 NaN,返回 false

4.3. 如果 x 的数字值和 y 相等,返回 true

4.4. 如果 x 是 +0 且 y 是 -0,返回 true

4.5. 如果 x 是 -0 且 y 是 +0,返回 ture

4.6. 返回 false

5. 如果 Type(x) 为 String,则当且仅当 x 与 y 的字符序列完全相同(长度相等,每个位置上的字符相同)时返回 true,否则返回 false

6. 如果 Type(x) 为 Boolean,则若 x 与 y 同为 true 或同为 false 时返回 true,否则返回 false

7. 如果 x 和 y 引用的是同一个对象,返回 true,否则返回 false

二、相等运算符 == 的实现
好了,当你明白了 === 的实现之后,我们再来看看 == 的实现,比较一下他们有何不同?
== 被称为 Equals Operator (注意看没有 Strict 了),假设有表达式 a == b,则它的实际运算过程如下
  1. 计算出表达式 a 的结果,并存入 lref 变量
  2. 将 GetValue(lref) 的结果存入 lval 变量
  3. 计算出表达式 b 的结果,并存入 rref 变量
  4. 将 GetValue(rref) 的结果存入 rval 变量
  5. 执行 Abstract Equality Comparison 算法判断 rval == lval 并将结果直接返回
注意,其中的前 4 个步骤是和 === 完全相同的。唯独 5 不同。对于 === 来说,调用的是
Strict Equality Comparison 算法,但是 == 则调用的是
Abstract Equality Comparison 算法。虽然仅一词之差,但是却有质的不同,我们下面就来看看到底它是怎么实现的
假设要计算的是 x == y,
Abstract Equality Comparison 计算的过程如下(很冗长,但是每个步骤都很简单)

1. 如果 Type(x) 和 Type(y) 相同,则

1.1. 如果 Type(x) 为 Undefined,返回 true

1.2. 如果 Type(x) 为 Null,返回 true

1.3. 如果 Type(x) 为 Number,则

1.3.1. 如果 x 是 NaN,返回 false

1.3.2. 如果 y 是 NaN,返回 false

1.3.3. 如果 x 的数值与 y 相同,返回 true

1.3.4. 如果 x 是 +0 且 y 是 -0,返回 true

1.3.5. 如果 x 是 -0 且 y 是 +0,返回 true

1.3.6. 返回 false

1.4. 如果 Type(x) 为 String,则当且仅当 x 与 y 的字符序列完全相同(长度相等,每个位置上的字符相同)时返回 true,否则返回 false

1.5. 如果 Type(x) 为 Boolean,则若 x 与 y 同为 true 或同为 false 时返回 true,否则返回 false

1.6. 如果 x 和 y 引用的是同一个对象,返回 true,否则返回 false

2. 如果 x 是 null 且 y 是 undefined,返回 true

3. 如果 x 是 undefined 且 y 是 null,返回 ture

4. 如果 Type(x) 为 Number 且 Type(y) 为 String,以 x == ToNumber(y) 的比较结果作为返回

5. 如果 Type(x) 为 String 且 Type(y) 为 Number,以 ToNumber(x) == y 的比较结果作为返回值

6. 如果 Type(x) 为 Boolean,以 ToNumber(x) == y 的比较结果作为返回值

7. 如果 Type(y) 为 Boolean,以 x == ToNumber(y) 的比较结果作为返回值

8. 如果 Type(x) 为 String 或 Number 且 Type(y) 为 Object,以 x == ToPrimitive(y) 的比较结果作为返回值

9. 如果 Type(x) 为 Object 且 Type(y) 为 String 或 Number,以 ToPrimitive(x) == y 的比较结果作为返回值

10. 返回 false

三、总结

从上面的算法流程可以看出,a === b 是最简单的。如果 a 和 b 的类型不同,那么一定会返回 false。而 a == b 则要灵活得多。JavaScript 会尝试调整 a 和 b 的类型,例如若 a 为字符串 b 为数字,则将字符串先转化为数字再与 b 比较,等等。这在很多时候简化了程序员的代码量。

一些程序员害怕 == 而提倡使用 === 的根本原因是,他们不知道在 == 的内部具体发生了什么。而这就导致误用和出错。

很多人认为,当我们不了解一个 feature 的时候,我们就不用它就行了。这也许是一种习惯性逻辑。但尴尬的是你不用这个 feature 没问题,别人却可能还是会用。为了能读懂别人的代码,我们又必须实际上搞清楚这内在的逻辑。所以最终还是得付出这方面的学习成本。

 

 

"==="叫做严格运算符,"=="叫做相等运算符。

严格运算符的运算规则如下,
(1)不同类型值
如果两个值的类型不同,直接返回false。
(2)同一类的原始类型值

同一类型的原始类型的值(数值、字符串、布尔值)比较时,值相同就返回true,值不同就返回false。

(3)同一类的复合类型值

两个复合类型(对象、数组、函数)的数据比较时,不是比较它们的值是否相等,而是比较它们是否指向同一个对象。

(4)undefined和null

undefined 和 null 与自身严格相等。

null === null  //trueundefined === undefined //true

 

相等运算符在比较相同类型的数据时,与严格相等运算符完全一样。

在比较不同类型的数据时,相等运算符会先将数据进行类型转换,然后再用严格相等运算符比较。类型转换规则如下:

(1)原始类型的值

原始类型的数据会转换成数值类型再进行比较。字符串和布尔值都会转换成数值,所以题主的问题中会有第二个string输出。

(2)对象与原始类型值比较

对象(这里指广义的对象,包括数值和函数)与原始类型的值比较时,对象转化成原始类型的值,再进行比较。

(3)undefined和null

undefined和null与其他类型的值比较时,结果都为false,它们互相比较时结果为true。

(4)相等运算符的缺点

相等运算符隐藏的类型转换,会带来一些违反直觉的结果。

'' == '0'           // false0 == '' // true 0 == '0' // true false == 'false' // false false == '0' // true false == undefined // false false == null // false null == undefined // true ' \t\r\n ' == 0 // true

这就是为什么建议尽量不要使用相等运算符。

至于使用相等运算符会不会对后续代码造成意外影响,答案是有可能会。

var a = undefined; if(!a){ console.log("1"); //1 }
var a = undefined; if(a == null){ console.log("1"); //1 }
var a = undefined; if(a === null){ console.log("1"); //无输出 }

也就是说当a为undefined时,输出的值会有变化,而在编程中对象变成undefined实在是太常见了。

 

 

 

 

var cmp = function(v1, v2) { return v1 == v2; };var vals = [        ["null", function() { return null; }],    ["undefined", function() { return undefined; }],    ["false", function() { return false; }],     ['"false"', function() { return "false"; }],    ["Boolean(false)", function() { return new Boolean(false); }],    ["[]", function() { return []; }],     ["[[]]", function() { return [[]]; }],     ['""', function() { return ""; }],    ['String("")',function(){
return new String('')}], ["0", function() { return 0; }], ["Number(0)",function(){
return new Number(0)}], ['"0"', function() { return "0"; }], ['String("0")',function(){
return new String('0')}], ["[0]", function() { return [0]; }], ["true", function() { return true; }], ['"true"', function() { return "true"; }], ["Boolean(true)", function() { return new Boolean(true); }], ["1",function() { return 1; }], ["Number(1)",function(){
return new Number(1)}], ['"1"', function() { return "1"; }], ['String("1")',function(){
return new String('1')}], ["[1]", function() { return [1]; }], ["-1", function() { return -1; }], ["Number(-1)",function(){
return new Number(-1)}], ['"-1"', function() { return "-1"; }], ['String("-1")',function(){
return new String('-1')}], ["[-1]", function() { return [-1]; }], ["Infinity", function() { return Infinity; }], ["-Infinity", function() { return -Infinity; }], ["{}", function() { return {}; }], ["NaN", function() { return NaN; }]];var canvas = document.getElementById("drawCanvas");var ctx = canvas.getContext("2d");var n = vals.length;var r = 40; // diameter of grid squaresvar p = 160; // padding space for labels// color grid cellsfor (var i = 0; i < n; i++) { var v1 = vals[i][1](); for (var j = 0; j < n; j++) { var v2 = vals[j][1](); var eq = cmp(v1, v2); ctx.fillStyle = eq ? "orange" : "white"; ctx.fillRect(p+i*r,p+j*r,r,r); }}// draw labelsctx.fillStyle = "black";var f = 24;ctx.font = f + "px Helvetica";for (var i = 0; i < n; i++) { var s = vals[i][0]; var w = ctx.measureText(s).width; ctx.save(); ctx.translate(p+i*r+r/2-f*0.4,p-w-2); ctx.rotate(3.14159/2); ctx.fillText(s, 0, 0); ctx.restore();}for (var i = 0; i < n; i++) { var s = vals[i][0]; var w = ctx.measureText(s).width; ctx.fillText(s, p-w-2, p+i*r+r/2+f*0.4);}// draw grid linesctx.beginPath();ctx.strokeStyle = "black";for (var i = 0; i <= n; i++) { ctx.moveTo(p+r*i, p); ctx.lineTo(p+r*i, p+r*n); ctx.moveTo(p, p+r*i); ctx.lineTo(p+r*n, p+r*i);}ctx.stroke();

 

 

 

 

转载于:https://www.cnblogs.com/lsgxeva/p/7967379.html

你可能感兴趣的文章
js添加删除行
查看>>
浏览器性能测试网址
查看>>
[MTK FP]用Python把图片资源image.rar中为.pbm后缀的文件更改为.bmp后缀的方法
查看>>
实验二
查看>>
[LeetCode]203. Remove Linked List Elements 解题小结
查看>>
测试一下
查看>>
vue base64
查看>>
【Django实战开发】案例一:创建自己的blog站点-1.安装及搭建开发环境
查看>>
Pie(二分)
查看>>
Mysql 索引优化
查看>>
09湖州二模(自选模块不等式)
查看>>
Mybatis Batch 批量操作
查看>>
Ubuntu server搭建Java web服务器
查看>>
WSGI学习系列WSME
查看>>
java读取xml配置文件和properties配置文件
查看>>
HDU 4300 Contest 1
查看>>
POJ 3311
查看>>
Button MouseEvent颜色变化
查看>>
Volist标签
查看>>
浅谈模块化
查看>>