# js中==和===的区别

``````操作数1 == 操作数2

``````

## 一、结论

1 `==` 抽象相等，比较时，会先进行类型转换，然后再比较值。
2 `===` 严格相等，会比较两个值的类型和值。
3 在明确知道操作数的数据类型情况下，建议使用 `===`；否则，使用 `==`

## 二、比较过程

#### 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.

#### ==

• 如果Type(x)和Type(y)相同，返回x===y的结果
• 如果Type(x)和Type(y)不同
• 如果x是null，y是undefined，返回true
• 如果x是undefined，y是null，返回true
• 如果Type(x)是Number，Type(y)是String，返回 x==ToNumber(y) 的结果
• 如果Type(x)是String，Type(y)是Number，返回 ToNumber(x)==y 的结果
• 如果Type(x)是Boolean，返回 ToNumber(x)==y 的结果
• 如果Type(y)是Boolean，返回 x==ToNumber(y) 的结果
• 如果Type(x)是String或Number或Symbol中的一种并且Type(y)是Object，返回 x==ToPrimitive(y) 的结果
• 如果Type(x)是Object并且Type(y)是String或Number或Symbol中的一种，返回 ToPrimitive(x)==y 的结果
• 其他返回false

#### 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.If Type(x) is Number, then
NOTE This algorithm differs from the SameValue Algorithm in its treatment of signed zeroes and NaNs.

#### ===

• 如果Type(x)和Type(y)不同，返回false
• 如果Type(x)和Type(y)相同
• 如果Type(x)是Undefined，返回true
• 如果Type(x)是Null，返回true
• 如果Type(x)是String，当且仅当x,y字符序列完全相同（长度相同，每个位置上的字符也相同）时返回true，否则返回false
• 如果Type(x)是Boolean，如果x,y都是true或x,y都是false返回true，否则返回false
• 如果Type(x)是Symbol，如果x,y是相同的Symbol值，返回true,否则返回false
• 如果Type(x)是Number类型
• 如果x是NaN，返回false
• 如果y是NaN，返回false
• 如果x的数字值和y相等，返回true
• 如果x是`+0`，y是`-0`，返回true
• 如果x是`-0`，y是`+0`，返回true
• 其他返回false

#### 可能一时半会有点不好理解，慢慢解释。

• Type(x) : 获取x的类型
• ToNumber(x) : 将x转换为Number类型
• ToBoolean(x) : 将x转换为Boolean类型
• ToString(x) : 将x转换为String类型
• SameValueNonNumber(x, y) : 计算非数字类型x, y是否相同
• ToPrimitive(x) : 将x转换为原始值

### 这里看下SameValueNonNumber()和ToPrimitive()两个操作。

#### SameValueNonNumber (x, y)

The internal comparison abstract operation SameValueNonNumber(x, y), where neither x nor y are Number values, produces true or false. Such a comparison is performed as follows:
1. Assert: Type(x) is not Number.
2. Assert: Type(x) is the same as Type(y).
3. If Type(x) is Undefined, return true.
4. If Type(x) is Null, return true.
5. If Type(x) is String, then
a. If x and y are exactly the same sequence of code units (same length and same code units at
corresponding indices), return true; otherwise, return false.
6. If Type(x) is Boolean, then
a. If x and y are both true or both false, return true; otherwise, return false.
7. If Type(x) is Symbol, then
a. If x and y are both the same Symbol value, return true; otherwise, return false.
8. Return true if x and y are the same Object value. Otherwise, return false.

• 断言：Type(x)不是Number类型
• 断言：Type(x)和Type(y)不同
• 如果Type(x)是Undefined，返回true
• 如果Type(x)是Null，返回true
• 如果Type(x)是String，当且仅当x,y字符序列完全相同（长度相同，每个位置上的字符也相同）时返回true，否则返回false
• 如果Type(x)是Boolean，如果x, y都是true或x, y都是false返回true，否则返回false
• 如果Type(x)是Symbol，如果x, y是相同的Symbol值，返回true,否则返回false
• 如果x和y是同一个对象值，返回ture，否则返回false

#### ToPrimitive ( input [ , PreferredType ] )

The abstract operation ToPrimitive takes an input argument and an optional argument PreferredType. The abstract operation ToPrimitive converts its input argument to a non‐Object type. If an object is capable of converting to more than one primitive type, it may use the optional hint PreferredType to favour that type.
Conversion occurs according to Table 9:
Table 9: ToPrimitive Conversions

Input Type Result
Undefined Return input.
Null Return input.
Boolean Return input.
Number Return input.
String Return input.
Symbol Return input.
Object Perform the steps following this table.

When Type(input) is Object, the following steps are taken:
1. If PreferredType was not passed, let hint be “default”.
2. Else if PreferredType is hint String, let hint be “string”.
3. Else PreferredType is hint Number, let hint be “number”.
4. Let exoticToPrim be ? GetMethod(input, @@toPrimitive).
5. If exoticToPrim is not undefined, then
a. Let result be ? Call(exoticToPrim, input, « hint »).
b. If Type(result) is not Object, return result.
c. Throw a TypeError exception.
6. If hint is “default”, let hint be “number”.
7. Return ? OrdinaryToPrimitive(input, hint).
When the abstract operation OrdinaryToPrimitive is called with arguments O and hint, the following steps are
taken:
8. Assert: Type(O) is Object.
9. Assert: Type(hint) is String and its value is either “string” or “number”.
10. If hint is “string”, then
a. Let methodNames be « “toString”, “valueOf” ».
11. Else,
a. Let methodNames be « “valueOf”, “toString” ».
12. For each name in methodNames in List order, do
a. Let method be ? Get(O, name).
b. If IsCallable(method) is true, then
i. Let result be ? Call(method, O).
ii. If Type(result) is not Object, return result.
13. Throw a TypeError exception.

NOTE When ToPrimitive is called with no hint, then it generally behaves as if the hint were Number. However, objects may over‐ride this behaviour by de ining a @@toPrimitive method. Of the objects de ined in this speci ication only Date objects (see 20.3.4.45) and Symbol objects (see 19.4.3.4) over‐ride the default ToPrimitive behaviour. Date objects treat no hint as if the hint were String.

#### ToPrimitive() 方法

js中的原始类型：

• Null: null值.
• Undefined: undefined 值.
• Number: 所有的数字类型，例如0,1,3.14等 以及NaN, 和 Infinity.
• Boolean: 两个值true和false.
• String: 所有的字符串，例如’abc’和’’.
其他的都是’非原始’的，像Array,Function,Object等。

ToPrimitive ( input [ , PreferredType ] )方法传递两个参数input和PreferredType，其中PreferredType是可选的。input输入,PreferredType可选的期望类型。
ToPrimitive 运算符把其值参数转换为非对象类型。如果对象有能力被转换为不止一种原语类 型,可以使用可选的 期望类型 来暗示那个类型。根据下表完成转换:

Undefined 不转换
Null 不转换
Boolean 不转换
Number 不转换
String 不转换
Symbol 不转换
Object 返回该对象的默认值。（调用该对象的内部方法[[DefaultValue]]一样）

• 如果PreferredType没有传，令hint为”default”
• 如果PreferredType参数是String类型，那么令hint为”string”
• 如果PreferredType参数是Number类型，那么令hint为”number”
• 令exoticToPrim为GetMethod(input, @@toPrimitive).
• 如果exoticToPrim不是undefined，那么
• 令result为 Call(exoticToPrim, input, « hint »).
• 如果result类型不是Object，直接返回result
• 扔出TypeError异常
• 如果hint为”default”,令hint为”number”
• 返回OrdinaryToPrimitive(input, hint)的值

• 断言：O的类型是Object
• 断言：hint的类型是String，它的值只能是’string’或’number’
• 如果hint是’string’
• 令methodNames是« “toString”, “valueOf” »
• 否则
• 令methodNames是« “valueOf”, “toString” ».
• 在有顺序的methodNames列表中，对于每个项目：
• 令method为Get(O, name).
• 如果IsCallable(method)返回true,然后
• 令result为Call(method, O).
• 如果result的类型不是Object，返回result
• 返回TypeError异常

### 看到这里如果你还没晕，说明你很厉害，那你应该接着往下看；反之，你更应该往下看了

``````// ECMA-262, section 9.1, page 30. Use null/undefined for no hint,
// (1) for number hint, and (2) for string hint.
function ToPrimitive(x, hint) {
// Fast case check.
// 如果为字符串，则直接返回
if (IS_STRING(x)) return x;
// Normal behavior.
if (!IS_SPEC_OBJECT(x)) return x;
if (IS_SYMBOL_WRAPPER(x)) throw MakeTypeError('symbol_to_primitive', []);
if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT;
return (hint == NUMBER_HINT) ? %DefaultNumber(x) : %DefaultString(x);
}
``````

#### DefaultNumber()方法：

``````// ECMA-262, section 8.6.2.6, page 28.
function DefaultNumber(x) {
if (!IS_SYMBOL_WRAPPER(x)) {
var valueOf = x.valueOf;
if (IS_SPEC_FUNCTION(valueOf)) {
var v = %_CallFunction(x, valueOf);
if (%IsPrimitive(v)) return v;
}

var toString = x.toString;
if (IS_SPEC_FUNCTION(toString)) {
var s = %_CallFunction(x, toString);
if (%IsPrimitive(s)) return s;
}
}
throw %MakeTypeError('cannot_convert_to_primitive', []);
}
``````
• 首先通过valueOf 转换，即 obj.valueOf()方法的返回值
• 如果 obj.valueOf()方法的返回值是原始类型，那么直接返回
• 如果不是，再通过 obj.toString()方法转换
• 如果obj.toString()返回的是原始类型，直接返回该值
• 如果还不是原始类型，抛出不能转换异常。

#### DefaultString()方法：

``````// ECMA-262, section 8.6.2.6, page 28.
function DefaultString(x) {
if (!IS_SYMBOL_WRAPPER(x)) {
// 转换为字符串原始类型时首先通过toString
var toString = x.toString;
if (IS_SPEC_FUNCTION(toString)) {
var s = %_CallFunction(x, toString);
if (%IsPrimitive(s)) return s;
}

// 否则通过valueOf
var valueOf = x.valueOf;
if (IS_SPEC_FUNCTION(valueOf)) {
var v = %_CallFunction(x, valueOf);
if (%IsPrimitive(v)) return v;
}
}
// 否则抛出异常
throw %MakeTypeError('cannot_convert_to_primitive', []);
}
``````
• 首先使用toString()转换
• 如果obj.toString()返回的是原始类型的值，直接返回该值
• 如果不是，再使用obj.valueOf()转换
• 如果obj.valueOf()返回的是原始类型的值，返回该值
• 如果还不是，抛出不能转换异常

#### 简单总结下：

• ToPrimitive(input,hint)转换为原始类型的方法，根据hint目标类型进行转换。
• hint只有两个值：String和Number
• 如果没有传hint，Date类型的input的hint默认为String,其他类型的input的hint默认为Number
• Number 类型先判断 valueOf()方法的返回值，如果不是，再判断 toString()方法的返回值
• String 类型先判断 toString()方法的返回值，如果不是，再判断 valueOf()方法的返回值

### 来两个简单的例子看一下ToPrimitive()的结果可能会更有效。

1. 求 ToPrimitive([10])
对于数组，默认的hint应该为Number ,所以先判断 valueOf()
``````> [10].valueOf()
[10]
``````

``````> [10].toString();
'10'
``````

toString()返回的是一个字符串 ‘10’ 是一个原始类型，因此，`ToPrimitive([10]) = '10'`

1. ToPrimitive(function sayHi(){})
``````var sayHi = function (name) {
console.log('hi ' + name);
}
console.log(sayHi.valueOf());
console.log(typeof sayHi.valueOf());
console.log(sayHi.toString());
console.log(typeof sayHi.toString());
``````

``````[Function]
function
function (name) {
console.log('hi ' + name);
}
string
``````

ToPrimitive(sayHi)是源码字符串。

Type(‘10’)为String,(10)为Number，因此结果变为 ToNumber(‘10’)==10
ToNumber(‘10’)的值是 数字 10 ，因此，最后要判断的是 10==10

[]==false也很简单了
false是Boolean类型的，我们要比较 []==ToNumber(false)即 []==0，就是上面这个啊，结果是 true

null==false的结果是false，==运算规则的最后一条，前面所有的都不满足，最后返回false，没什么好纠结的。
null==false的结果是false，但这并不代表 null==true 。因为 null==true 最后走的还是最后一条，返回false。

# 全文毕

### 推荐阅读更多精彩内容

• pyspark.sql模块 模块上下文 Spark SQL和DataFrames的重要类： pyspark.sql...
mpro阅读 6,280评论 0 11
• Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
苏黎九歌阅读 9,309评论 0 39
• Javascript 中有6种基本类型(包括 symbol)，以及对象类型，他们在不同的运算中会被系统转化为不同是...
faremax阅读 287评论 0 3
• JavaScript 中 == 和 === 的区别 和其他语言有些不同，在 JavaScript 中除了用==操作...
融合xx阅读 1,772评论 0 2
• 被噩梦惊醒的一瞬 世界是如此透彻 汽笛穿过五百道院墙 在你的耳边翻滚 安静的人费力调整着粗重的呼吸 路灯旁，被人忽...
紫章阅读 60评论 0 0