JS开发者应懂的33个概念系列5(下)&&16--typeof 与 instanceof && 17--原型继承与原型链

488 阅读3分钟

typeof的原理

typeof可以用来判断原始值的类型,以及区分对象值和原始值.我们可以利用 typeof 来判断number, string, object, boolean, function, undefined, symbol 这七种类型。

一个 js 的变量,在它的底层实现中, 类型信息是怎么实现的呢?也就是说js 在底层是怎么存储数据的类型信息呢?typeof也就是通过类型信息进行判断的。

js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息:

  • 000 object
  • 010 浮点数
  • 100 string
  • 110 boolean
  • 1 整数

对于 undefinednull 来说,这两个值的信息存储是有点特殊的。

  • null:所有机器码均为0
  • undefined:用 −2^30 整数来表示

所以,typeof在判断 null的时候就出现问题了,由于 null 的所有机器码均为0,因此直接被当做了对象来看待。所以,在判断变量类型的时候,避免对null进行判断。

typeof null   // "object"

instanceof的原理

在 JavaScript 中,判断一个变量的类型尝尝会用 typeof 运算符,在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 "object"

直接上硬货:

function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
 var O = R.prototype;// 取 R 的显示原型
 L = L.__proto__;// 取 L 的隐式原型
 while (true) { 
   if (L === null) 
     return false; 
   if (O === L)// 这里重点:当 O 严格等于 L 时,返回 true 
     return true; 
   L = L.__proto__; 
 } 
}

instanceof 在查找的过程中会遍历左边变量原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。

划重点,原型链

原型链

function Person() {}
var Student = new Person()

先不着急解释原型链,先看一下什么是原型?

原型

  • 每一个构造函数都拥有一个prototype属性,这个属性指向一个对象,也就是原型对象。比如:构造函数Personprototype便是指向Person.prototype对象。
  • 原型对象默认拥有一个constructor属性,指向它的那个构造函数(也就是说构造函数和原型对象是互相指向的关系)。比如:Person.prototype.constructor指向Person
  • 每个对象类型比如(Student,Person.prototype,Function.prototype)都拥有一个隐藏的属性[[prototype]],指向它的原型对象,这个属性可以通过 Object.getPrototypeOf(obj)obj.__proto__来访问。
  • 实际上,构造函数的prototype属性与它创建的实例对象的[[prototype]]属性指向的是同一个对象,即Student.__proto__ === Person.prototype

JavaScript中,所有的对象都是由它的原型对象继承而来,反之,所有的对象都可以作为原型对象存在。

访问对象的属性时,JavaScript会首先在对象自身的属性内查找,若没有找到,则会跳转到该对象的原型对象中查找,也就是通过__proto__进行查找。

所以呢,原型链就是你查找过程所经历的地方。

最后来个例子:

console.log(Object instanceof Object);//true 
console.log(Function instanceof Function);//true 
console.log(Function instanceof Object);//true 
 

在复习一遍:

Object instanceof Object?

var O = Object.prototype;
var L = Object.__proto__; // L是Function.prototype
while(true) // 进入循环
L = Object.__proto__.__proto__ // L是Object.prototype
while(true) // 重新进入循环
O === L 
return true

总结口诀

  • Object.__proto__ === Function.prototype其中Object是构造函数
  • 指向Function.prototype是构造函数的__proto__属性
  • 指向Object.prototype是原型对象的__proto__属性
  • Object.prototype.__proto__null
  • *.prototype.constructor指向它的构造函数*
  • Object.prototype除了constructor__proto__外,还有toString(),valueOf()等属性,下属原型对象可以通过原型链继承这些属性。