Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

你真的理解==和===的区别吗? #10

Open
FrankKai opened this issue Mar 2, 2018 · 0 comments
Open

你真的理解==和===的区别吗? #10

FrankKai opened this issue Mar 2, 2018 · 0 comments

Comments

@FrankKai
Copy link
Owner

FrankKai commented Mar 2, 2018

用中文怎么叫合适?
相等?全等?
其实并不合适,叫double equals 或者treble equals,或者叫不懂的人觉得比较不专业的双等或者三等操作符,是更加严谨和正确的叫法。
为什么这么说?看完这篇博客你就明白了。

一、入门阶段:自我经验(一脚一坑)

我的理解是:
==是相等,值相等,返回true。
===是全等,值相等,类型也相等,返回true。

上面的理解是错的,[]==false[1]===[1]返回就可以推翻。[]==false,他们的值并不相等,但是返回true。[1]和[1],值相等,类型也相等,返回为false。因此上面理解是错的。

正确的理解是:

==是相等,先转换再比较,返回true。
===是全等,不转换就比较,返回true。

[]==false,false是转换为0,[]强制转换成0(解释不清楚),0 == 0 ,返回为true。
[1] === [1],不转换就比较,[1]===[1],左右的[1]指向内存中两个独立的,地址不同的数组,故返回false。

看下最简单的例子:
①基础类型vs基础类型
1== true //true
1 === true //false
再看两个复杂的例子:
②对象vs基础类型*
[] == false //true
[] === false //false
③对象vs对象
{age:6} == {age:6} //false
{age:6} === {age:6} //false
[1] == [1] //false
[1] === [1] //false

二、初级阶段:参考书籍(勉强避雷)

聪明的你会问了,[] == falsefalse == []的结果一致吗?
答案是一致的,因为无论再操作符左侧还是右侧,它们都是操作数,位置是没有关系的。

为什么会出现上面的结果?

为什么 1 == true[] == false返回true?
因为type coercion的存在,高设翻译为强制转型。
为什么会出现强制转换类型?
强制转换了谁的类型?
转换成了什么类型?

为什么{age:6} == {age:6}返回的是false?
他们看起来不是一样的吗,都是一个object,而且内部数据都是age:6,key-value值一模一样,为什么不返回true呢?

如果再在操作数中加入nullundefined这两个神奇的类型呢?
问题就变的更复杂了...

来看下《Javascript高级程序设计》关于==和===的规则

1.如果有一个操作数是布尔值,则在比较前先将其转换为数值,true转换为1,false转换为0,例如false == 0,true == 1
2.如果一个操作数是字符串,另一个操作数是数值,先将字符串转换成数值,例如"1"==1,'' ==0
3.如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,用得到的基本类型按照前面的规则进行比较。(解释不清楚)
4.null和undefined是相等的。
5.如果有一个数是NaN,则相等操作符返回false,而不想等操作符返回true。NaN == NaN返回为false,因为规则如此。
6.如果两个操作数是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回true,否则返回false。
例如:var obj = {a:1};foo = obj;bar = obj;foo==bar;foo==bar返回为true,因为他们指向同一个对象,obj。

===和==的规则类似,唯一少了转换的一步。
第6步中的foo===bar返回true,如果不明白为什么?请看第三部分。

三、高级阶段:参考规范(真正理解)

真的如高设所说的那样吗?其实不然。
下面是ecma-262的规范,其中有对==和===的执行定义,把解释不清楚干掉。
https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
7.2.13 Abstract Equality Comparison

The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed
as follows:
1. If Type(x) is the same as Type(y), then
a. Return the result of performing Strict Equality Comparison x === y.
2. If x is null and y is undefined, return true.
3. If x is undefined and y is null, return true.
4. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
5. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
6. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
7. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
8. If Type(x) is either String, Number, or Symbol and Type(y) is Object, return the result of the
comparison x == ToPrimitive(y).
9. If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the
comparison ToPrimitive(x) == y.
10. Return false.

7.2.14 Strict Equality Comparison

The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed
as follows:
1. If Type(x) is different from Type(y), return false.
2. If Type(x) is Number, then
a. If x is NaN, return false.
b. If y is NaN, return false.
c. If x is the same Number value as y, return true.
d. If x is +0 and y is ‑0, return true.
e. If x is ‑0 and y is +0, return true.
f. Return false.
3. Return SameValueNonNumber(x, y).
NOTE This algorithm differs from the SameValue Algorithm in its treatment of signed zeroes and
NaNs.

1.[]==false
来分析一个经典的例子:[]==false,看完彻底理解==的强制转换。
①[]==false→**[]==0**

7.If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).


经过ToNumber(false),false会被转换为0.
②[]==0→**''==0**

9.If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the
comparison ToPrimitive(x) == y

这个时候就比较复杂了...

按照规范,我们需要经过下面的一系列操作

→OrdinaryToPromitive([],default)
→OrdinaryToPromitive([],number)
→Get([],valueOf)
→Call(valueOf,[])
→Get([],toString)
→Call(toString,[])
→''

不要慌,用Javascript来描述,还是很简单的:

[].valueOf().toString()

③''==0→0==0

  1. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.

2.[1]===[1]
再来看下===操作符,其中有句话可以完美解释[1]===[1]返回false,但是var obj = {a:1};foo = obj;bar = obj;foo===bar中foo===bar返回为true的原因。

  1. Return SameValueNonNumber(x, y).

由于[1]===[1]三等号左右的[1],不是same Object,因此返回为false.
而foo===bar,三等号左右其实本质上都是指向obj这个对象,值相等更是必然,所以返回为true。

我们由此可以举一反三,[1]==true返回true,而[1,2,3]==true返回false的原因也不足为奇了。

如有错误欢迎指正说明,期待和你交流~
努力成为优秀的前端工程师~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant