== vs ===, typeof vs instanceof
用来放一些我看的书籍和学习的记录,欢迎点赞和讨论。
严格相等 ===
严格相等进行比较前不会进行隐式转换。
比较步骤:
- 首先判断是不是相同类型,如果不是则是不严格相等
- 类型相同,值也相同并且不是 number 类型时,两个值全等
- number 类型时,如果两个值都不是 NaN,值相同时或者两个值分别为 +0 和 -0,两个值全等。
NaN === NaN // false
非严格相等 ==
在比较前进行类型转换成相同类型的,然后进行严格相等校验。
在类型转换时有些规律
- number 和 string 进行比较时会先转换成 number
- number 和 boolean 进行比较时会先转换成 number
- string 和 boolean 进行比较时会先转换成 number
- 其中一方是 Object 会先转换成原始值。
整体的判断流程就是
- 类型是否相同,相同的话判断值是否相同。
- 其中一方是 null 或者 undefined , null 和 undefined 只和自己相等。
- 其中一方是 boolean ,将 boolean 转换成 number 。
- 其中一方是 Object 先转换成原始值,优先toString。
[] == ![] 现在应该能正确判断了吧
首先是右边是个表达式,由前两节可知道 [] 转换成 boolean 为 true ,非运算之后就是 false, 此时的左边是 object 右边是 boolean ,执行第四步 为 '', 将 '' 转换成数字0, false 转换成数字是 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 判断原始类型的类型
// Numbers
typeof 1 === 'number';
typeof 3.14 === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管NaN是"Not-A-Number"的缩写,意思是"不是一个数字"
typeof Number(1) === 'number'; // 不要这样使用!
// Strings
typeof "" === 'string';
typeof "bla" === 'string';
typeof (typeof 1) === 'string'; // typeof返回的肯定是一个字符串
typeof String("abc") === 'string'; // 不要这样使用!
// Booleans
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(true) === 'boolean'; // 不要这样使用!
// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';
// Undefined
typeof undefined === 'undefined';
typeof blabla === 'undefined'; // 一个未定义的变量,或者一个定义了却未赋初值的变量
// Objects
typeof {a:1} === 'object';
// 使用Array.isArray或者Object.prototype.toString.call方法可以从基本的对象中区分出数组类型
typeof [1, 2, 3] === 'object';
typeof new Date() === 'object';
// 下面的容易令人迷惑,不要这样使用!
typeof new Boolean(true) === 'object';
typeof new Number(1) ==== 'object';
typeof new String("abc") === 'object';
// 函数
typeof function(){} === 'function';
typeof Math.sin === 'function';
typeof 对于 null date array object RegExp 返回值都是 object 在做类型比较的时候不是很精确。
instanceof 判断对象的类型
语法:
typeof operand
operand:对象或者原始值
instanceof运算符用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置
object instanceof constructor
object: 要检测的对象 // 必须是对象呢
constructor: 某个构造函数
instanceof 典型的用法是判断是否继承关系,用于测试对象是不是特定构造函数的实例。
实现instanceof 要点:
- obj 是null 或者不是对象的时候返回 false
- 每个实例对象都有一个私有属性( proto )指向它的原型对象Prototype
- 该原型对象也有一个自己的原型对象( proto ) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
function 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
问题:
var y = 1, x = y = typeof x;
x;
表达式是从右往左的,x由于变量提升,类型是undefined,所以x=y="undefined"。
(function f(f){
return typeof f();//"number"
})(function(){ return 1; });
传入的参数为 f 是function(){ return 1; }这个函数。通过f()执行后,得到结果1,所以typeof 1返回"number"。这道题很简单,主要是区分f和f()。
'use strict'
var foo = {
bar: function() { console.log(this);return this.baz; },
baz: 1
};
(function(){
return typeof arguments[0]();//"undefined" function() { return window.baz; }
})(foo.bar); // function() { return this.baz; }
this 当前执行代码的环境对象,这里的执行环境是自执行函数,他的 this 指向 Arguments。
var foo = {
bar: function(){ console.log(this);return this.baz; },
baz: 1
}
typeof (f = foo.bar)();//undefined
这里的执行环境是自执行函数,他的 this 指向 window
var f = (function f(){ return "1"; }, function g(){ return 2; })();
typeof f;//"number"
自执行函数和 分组选择符 的使用, 分组选择符通过 , 隔开取最后一个值
常见面试题
null == undefined // true
null === undefined // false
0 == '0'// true
false == '0'// true
[] == '0' // false
[] == '' // true
typeof null == 'object'
有时候会让你判断下面代码有什么问题
if (typeof obj === 'object')
obj 为 null 时为真