Javascript 中 == 和 === 区别是什么?
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
- 红色:===
- 橙色:==
- 黄色:<= 和 >= 同时成立,== 不成立
- 蓝色:只有 >=
- 绿色:只有 <=
&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;gt; (参: , )
顺便,有人说这图像现代艺术,感觉旋转完更像,删减重排换成 S1 配色之后做成头像了。 不免费帮人做头像(也就是换个顺序的事情) &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;gt;
- 计算出表达式 a 的结果,并存入 lref 变量
- 将 GetValue(lref) 的结果存入 lval 变量
- 计算出表达式 b 的结果,并存入 rref 变量
- 将 GetValue(rref) 的结果存入 rval 变量
- 执行 Strict Equality Comparison 算法判断 rval === lval 并将结果直接返回
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,则它的实际运算过程如下- 计算出表达式 a 的结果,并存入 lref 变量
- 将 GetValue(lref) 的结果存入 lval 变量
- 计算出表达式 b 的结果,并存入 rref 变量
- 将 GetValue(rref) 的结果存入 rval 变量
- 执行 Abstract Equality Comparison 算法判断 rval == lval 并将结果直接返回
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();