# instanceof 和 typeof 原理回顾
# instanceof
# 概念
- 官方定义: 
instanceof运算符用来检测构造函数的prototype属性是否出现在某个实例对象的原型链上. - 通俗的讲: 
instanceof用来判断某个对象是否为某个构造函数的实例. - 形象的讲: 沿着操作符左边对象的proto这条线查找,沿着操作符右边对象的prototype查找.若两条线能找到同一个引用,则返回
true.若到终点还未相交,则返回false. 
# 语法
object instanceof constructor  // object为要测试的实例对象    constructor为构造函数 
 1
注意: instanceof 无法判断基本类型,只能判断引用类型
let obj = new Object()
console.log(obj instanceof Object)  // true
class Person {}
const p = new Person()
console.log(p instanceof Person)  // true
// 判断 f 是否是 F 类的实例
function F(){}
const f = new F()
console.log(f.__proto__ === F.prototype)  // true   因为F的prototype === f的__proro__ 符合 instanceof 检测条件,所以下面为true
console.log(f instanceof F)  // true
 1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
下面的代码说明了 Date 也属于 Object 类型, Date 是由 Object 类派生出来的
const d = new Date()
console.log(d instanceof Date)  // true
console.log(Date instanceof Object)  // true
console.log(d instanceof Object)  // true
 1
2
3
4
2
3
4
# 练习解题
# 题型1
console.log(Function instanceof Function)  
console.log(Function instanceof Object)
console.log(Object instanceof Function)
console.log(Object instanceof Object)
 1
2
3
4
2
3
4
思路如下:
console.log(Function.__proto__ === Function.prototype)
console.log(Function.__proto__.__proto__ === Object.prototype)
console.log(Object.__proto__ === Function.prototype)
console.log(Object.__proto__.__proto__ === Object.prototype)
 1
2
3
4
2
3
4
# 题型2
function Fun(){}
const f = new Fun()
console.log(f instanceof Fun)  // true
function Fun2(){return {}}
const f2 = new Fun2()
console.log(f2 instanceof Fun2)  // false
 1
2
3
4
5
6
7
2
3
4
5
6
7
因为 instanceof 操作符是判断原型链上的对象,而当一个对象并不是通过原型构造出来的时候(直接return一个对象),此方法就失效了.
# 模拟实现instanceof函数
 function instanceOf(obj, constructor){
  if(obj === null){
    return false
  }
  if(typeof obj !== 'object' && typeof obj !== 'function' ){
     return false
  }
  let proto = obj.__proto__
  while(proto){
    if(proto === constructor.prototype){
      return true
    }
    proto = proto.__proto__
  }
  return false
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# typeof
# 概念
typeof 操作符返回一个字符串,表示未经计算的操作数的类型
# 语法
typeof operand
typeof(operand)  // operand 是一个表示对象或原始值的表达式,其类型将被返回
 1
2
2
# 历史发展
在很早之前,使用的32位系统,为了性能考虑使用低位存储了变量的类型信息.
- 000 对象
 - 1 整数
 - 010 浮点数
 - 100 字符串
 - 110 布尔
 
此外还有2个比较特殊的指: undefined 和 null
- undefined 用 (-2^30) 表示
 - null 对应机器码的 NULL 指针,一般是全零
 
这样一来,null 就出了一个bug.因为它对应的空指针,低位是000,因此被判断成一个对象了.且这个bug,应该是永远都不会去修复了.
# 可检测类型
console.log(typeof undefined)  // undefined
console.log(typeof null)  // object
console.log(typeof 123n)  // bigint
console.log(typeof Symbol('str'))  // symbol
console.log(typeof (() => {}))  // function
console.log(typeof {})  // object
 1
2
3
4
5
6
2
3
4
5
6
在ES2015之前,typeof 总能保证对任何所给的操作数返回一个字符串,即使是未声明的标识符,也能返回undefined. 但是在有了let 和 const 块级作用域后,在其被声明之前对块中的let 和 const 变量使用 typeof 将会抛出一个 ReferenceError .
console.log(typeof obj2)  // Uncaught ReferenceError: Cannot access 'obj2' before initialization
const obj2 = {}
 1
2
2
当前所有的浏览器都暴露了一个类型为 undefined 的非标准宿主对象 document.all
console.log(typeof document.all)  // undefined
 1
# 获取类型的终结方案
我们通过 toString 来获取类型,算是一个比较完美的方案.
function getType(obj){
  let reg = /\[object\s(.+)\]/
  let type = Object.prototype.toString.call(obj)
  return type.replace(reg, '$1').toLowerCase()
}
// 或者下面的写法
function getType(obj){
  let type = Object.prototype.toString.call(obj)
  let reg = /\[object\s([^\s]+)\]/g
  if(reg.test(type)){
    return RegExp.$1.toLowerCase()
  }
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 总结
通常,我们使用 typeof 来判断基本类型 , instanceof 判断引用类型.
参考链接:
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/instanceof (opens new window)
 - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof (opens new window)
 - https://developer.ibm.com/zh/articles/1306-jiangjj-jsinstanceof/ (opens new window)
 - https://blog.csdn.net/LL18781132750/article/details/81115081 (opens new window)
 - https://juejin.im/post/6844904081803182087 (opens new window)
 - https://juejin.im/post/6844903850395058190 (opens new window)
 - https://juejin.im/post/6844904089369706504 (opens new window)
 - https://juejin.im/post/6844904199700873223 (opens new window)
 
← Storage对象 js中容易忽略的参数 →