JavaScript进阶系列- == vs ===, typeof vs instanceof
严格相等 ===
严格相等进行比较前不会进行隐式转换。
比较步骤:
- 首先判断是不是相同类型,如果不是则是不严格相等
- 类型相同,值也相同并且不是 number 类型时,两个值全等
- number 类型时,如果两个值都不是 NaN,值相同时或者两个值分别为 +0 和 -0,两个值全等。
1 | NaN === NaN // false |
非严格相等 ==
在比较前进行类型转换成相同类型的,然后进行严格相等校验。
在类型转换时有些规律
- number 和 string 进行比较时会先转换成 number
- number 和 boolean 进行比较时会先转换成 number
- string 和 boolean 进行比较时会先转换成 number
- 其中一方是 Object 会先转换成原始值,在进行 == 判断。
整体的判断流程就是
- 类型是否相同,相同的话判断值是否相同。
- 其中一方是 null 或者 undefined , null 和 undefined 只和自己相等。
- 其中一方是 boolean ,将 boolean 转换成 number 。
- 其中一方是 Object 将根据另外一个的类型转换成对应的类型。
[] == ![] 现在应该能正确判断了吧
首先是右边是个表达式,由前两节可知道 [] 转换成 boolean 为 true ,非运算之后就是 false, 此时的左边是 object 右边是 boolean ,执行第三步右边为 0, 然后将 object 转换成数字, [] 转换成数字是 0, 所以 0===0。
比较值列表 | ||||||
---|---|---|---|---|---|---|
\ | Undefined | Null | Number | String | Boolean | Object |
Undefined | true | true | false | false | false | IsFalsy(B) |
Null | true | true | false | false | false | IsFalsy(B) |
Number | false | false | A === B | A === ToNumber(B) | A=== ToNumber(B) | A=== ToPrimitive(B) |
String | false | false | ToNumber(A) === B | A === B | ToNumber(A) === ToNumber(B) | ToPrimitive(B) == A |
Boolean | false | false | ToNumber(A) === B | ToNumber(A) === ToNumber(B) | A === B | ToNumber(A) == ToPrimitive(B) |
Object | false | false | ToPrimitive(A) == B | ToPrimitive(A) == B | ToPrimitive(A) == ToNumber(B) | A === B |
- ToNumber(A) 尝试在比较前将参数 A 转换为数字,这与 +A(单目运算符+)的效果相同。
- ToPrimitive(A)通过尝试调用 A 的A.toString() 和 A.valueOf() 方法,将参数 A 转换为原始值(Primitive)。
typeof vs instanceof
typeof 判断原始类型的类型
1 | // Numbers |
typeof 对于 null date array object RegExp 返回值都是 object 在做类型比较的时候不是很精确。
instanceof 判断对象的类型
语法:1
2
3
4
5
6
7typeof operand
operand:对象或者原始值
instanceof运算符用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置
object instanceof constructor
object: 要检测的对象 // 必须是对象呢
constructor: 某个构造函数
instanceof 典型的用法是判断是否继承关系,用于测试对象是不是特定构造函数的实例。
实现instanceof
要点:
- obj 是null 或者不是对象的时候返回 false
- 每个实例对象都有一个私有属性( proto )指向它的原型对象Prototype
- 该原型对象也有一个自己的原型对象( proto ) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18function myinstanceof(obj, constructor){
if(obj === null || typeof obj !== 'Object'){ // 去除Null和不是对象的情况
return false
}
// 获得构造函数的原型对象
const prototype = constructor.prototype
// 获取对象的原型
let _proto = obj.__proto__ // 推荐使用 Object.getPrototypeOf(object)
while(true){
if(_proto === null){ // 最后一个环节
return false
}
if(_proto === prototype){
return true
}
_proto = obj.__proto__
}
}
参考:
mdn原型链
浅谈 instanceof 和 typeof 的实现原理
mdn instanceof
问题:1
2var y = 1, x = y = typeof x;
x;
表达式是从右往左的,x由于变量提升,类型是undefined,所以x=y=”undefined”。
1 | (function f(f){ |
传入的参数为 f 是function(){ return 1; }这个函数。通过f()执行后,得到结果1,所以typeof 1返回”number”。这道题很简单,主要是区分f和f()。
1 | 'use strict' |
this 当前执行代码的环境对象,这里的执行环境是自执行函数,他的 this 指向 Arguments。
1 | var foo = { |
这里的执行环境是自执行函数,他的 this 指向 window
1 | var f = (function f(){ return "1"; }, function g(){ return 2; })(); |
自执行函数和 分组选择符 的使用, 分组选择符通过 , 隔开取最后一个值
常见面试题
1 | null == undefined // true |
typeof null == ‘object’
有时候会让你判断下面代码有什么问题1
if (typeof obj === 'object')
obj 为 null 时为真