为什么 `[] == []` 为 `false,[] == ![]` 为 true
相信很多面试题里都会出现“[]==![]的输出结果”这么一个题目,以前我也被问过,这个题目的结果很出乎意料居然是true,困惑了很久,一直懒得查相关资料,也就当做一个特例记下来了;最近又有一次机会碰到了这个题目,所以,这次决定要好好查查,一定要整明白,于是就有了这篇文章
怎么理解 [] == [] 为 false
这个问题很好理解,两个对象的实例化,并不相等,就像
1 | var a = new Object(); |
更深一层次的理解,可以把堆和栈两个东西搬出来。
js里面,有一个特殊的数据类型分类:基本类型、引用类型。
基本类型值包括:String,Number,Boolean,undefined,null;
引用类型值包括:Object,Array,Function,基本类型的原始类型的引用类型,以及es6新出的一些复杂数据类型;
基本类型的数值是存在栈的简单数值,而引用类型则是将实际数值存放在堆里,并同时在栈中保存一下这个实际数值的指针,这就是如何理解以下例子的原理
1 | var a = {a:1,b:2} |
当堆里的值发生变化的时候,所有指向这个值的指针,都会拿到变化后的值
声明引用类型的时候,程序每次都会创建出一个新的实例,存放在堆里不同的地址,引用类型数据保存的只是指向这个地址的指针,而引用类型在进行比较的时候,也就是比较两个对象的堆内存中的地址是否相同,我们上面提到的[] == []这个命题中,等式前后,都是新声明的一个空数组的实例化对象,分别会存放在两个不同的地址,因为地址不同,所以结果为false。
怎么理解 [] == ![] 为 true
首先,== 的比较规则,最后都是转换成 Number 来比较的。
== 的定义是:
The production EqualityExpression : EqualityExpression == RelationalExpression is evaluated as follows:
- Let lref be the result of evaluating EqualityExpression.
- Let lval be GetValue(lref).
- Let rref be the result of evaluating RelationalExpression.
- Let rval be GetValue(rref).
- Return the result of performing abstract equality comparison rval == lval. (see 11.9.3).
上面提到比较的行为在 11.9.3 节里,所以翻到 11.9.3:
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
- If Type(x) is the same as Type(y), then
- If Type(x) is Undefined, return true.
- If Type(x) is Null, return true.
- If Type(x) is Number, then
- If x is NaN, return false.
- If y is NaN, return false.
- If x is the same Number value as y, return true.
- If x is +0 and y is −0, return true.
- If x is −0 and y is +0, return true.
- Return false.
- If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false.
- If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
- Return true if x and y refer to the same object. Otherwise, return false. - If x is null and y is undefined, return true.
- If x is undefined and y is null, return true.
- If Type(x) is Number and Type(y) is String,return the result of the comparison x == ToNumber(y).
- If Type(x) is String and Type(y) is Number,return the result of the comparison ToNumber(x) == y.
- If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
- If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
- If Type(x) is either String or Number and Type(y) is Object,return the result of the comparison x == ToPrimitive(y).
- If Type(x) is Object and Type(y) is either String or Number,return the result of the comparison ToPrimitive(x) == y.
- Return false.
- 在这段算法里,我们看到由于数组不是基本类型,需要先 ToPrimitive([])转换成原始类型, 即 “”。
接下来 ToNumber(“”), 即 0。 - ![], 即 false。
结果,[] == ![] 的比较最后落到了 0 == 0 上,所以结果为 true。
参考:
https://www.zhihu.com/question/29615998/answer/45667956
http://www.uw3c.com/jsviews/js102.html