likes
comments
collection
share

typeof 和 instanceof 实现原理

作者站长头像
站长
· 阅读数 9

1.typeof

1.基本使用

typeof 返回的是变量的基本类型。JavaScript 中包括基本数据类型引用类型,通常用于对变量所持有的值的判断,使用 typeof,结果可能是 8 种:

numberstringobjectbooleansymbolfunctionundefinedbigInt

2.实现原理:

typeof 是通过判断数值的机器码的低位来判断类型的。

最初的版本,JS 中数值是以 32位 格式存储,由 类型标记位(1-3位)真实值 组成,类型标记存储在低位,其中几种类型如下:

  • 000 表示对象
  • 001 表示整型int
  • 010 表示双精度浮点型(double
  • 100 表示 string
  • 110 表示 boolean

3.缺陷:

因为 JavaScript 的变量是没有类型的,所以判断类型都是对变量所持有的值的判断。使用 typeof 对未声明 和 目前没有值的 变量进行判断的处理是非常不好的。这本事两种完全不同的情况,但是浏览器的处理结果却是一样的,如下:

typeof 和 instanceof 实现原理

对于没有被声明的 abcnnn 和 声明却没有赋值的 p ,返回结果却都是 undefined

typeof abcnnn  // ReferenceError:abcnnn is not defined
let p
typeof p // undefined
// 强调!!!‘is not defined’ 和‘undefined’ 是两码事
// 或许 ‘is not defined’ 改成 ‘is not declared’ 会好点

2.instanceof

1.基本使用

instanceof 返回一个布尔值。因为引用类型保存在栈中的是一个地址,所以没有办法通过 typeof 找到数值判断机器码。要使用另外一个 instanceof 来判断。

数据 instanceof 类型; // 返回 true or false

instanceof 是判断一个示例是否属于某一种类型。

2.实现原理:

通过在原型链上查找,跟判断的类型对比,如果查找到一样的,返回 true,否则返回 false

const instanceOf = (leftVaule,rightVaule) => {
  const rightProto = rightVaule.prototype;
  leftVaule  =  leftVaule.__proto__;
  while(true){
    if (leftVaule === null){
      return false;
    }
    if(leftVaule === rightProto){
      return true;
    }
    leftVaule = leftVaule.__proto__;
  }
}

补充:

在 ES6 中,instanceof 操作符会使用 Symbol.hasInstance 函数来确定关系。 根据 ECMAScript 规范,这个符号作为一个属性表示 :一个方法,该方法决定一个构造器对象是否认可一个对象是它的实例。

typeof 和 instanceof 实现原理

这个属性定义在 Function 的原型上,因此默认在所有函数和类上都可以调用。由于 instanceof 操作符会在原型链上寻找这个属性定义,就跟在原型链上寻找其他属性一样,因此可以在继承的类上通 过静态方法重新定义这个函数:

class Bar {}
class Baz extends Bar {
  static [Symbol.hasInstance]() {
    return false;
  }
}
let b = new Baz(); 
console.log(Bar[Symbol.hasInstance](b)); // true 
console.log(b instanceof Bar); // true 
console.log(Baz[Symbol.hasInstance](b)); // false 
console.log(b instanceof Baz); // false

3.注意

但是由于 Array 等引用类型本质上也都是对象,所以示例如下:

const a = [];
console.log(a instanceof Object)  // true

3.Object.prototype.toString.call()


console.log(Object.prototype.toString.call([]))    // [object Array]
console.log(Object.prototype.toString.call({}))    // [object Object]
console.log(Object.prototype.toString.call(true))   // [object Boolean]

console.log(Object.prototype.toString.call(100))    // [object Number]
console.log(Object.prototype.toString.call('starry')) // [object String]

console.log(Object.prototype.toString.call(null))     // [object Null]
console.log(Object.prototype.toString.call(undefined))  // [object Undefined]


console.log(Object.prototype.toString.call(new Set()))   // [object Set]
console.log(Object.prototype.toString.call(new Map()))   // [object Map]

总结:

typeof instanceof 都有弊端,并不能满足所有场景的需求

  1. typeof 会返回一个变量的基本类型,instanceof 返回的是一个布尔值。
  2. instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型。
  3. typeof 可以判断基础数据类型(null 除外),但是引用数据类型中,除了 function 类型以外,其他的也无法判断。
  4. 如果需要通用检测数据类型,可以采用 Object.prototype.toString.call

参考资料: 1.JavaScript 高级程序设计 2.The history of “typeof null”