概述
js中可以通过typeof操作符和instanceof操作符判断变量的类型。而typeof在判断基本类型的变量时能精准判断。当变量是数组、对象时都只会返回‘object',无法准确的说明该对象是什么类型的。但是instanceof基于原型链可以判断一个引用是否属于某构造函数。能弥补typeof 方法判断变量类型的缺点。本文旨在分析instanceof的底层原理,同时借此复习原型以及原型链的知识。一、js中变量类型
本节先来回顾一下js的变量类型,js变量可以分为基本类型和引用类型。(1)基本类型:字符串(string)、数值(number)、布尔值(boolean)、undefined、Null、Symbol
(2)引用类型:对象(Object)
基本类型和引用类型的区别基本类型:
1、值类型的变量值存储在栈中,而引用类型的变量值 存储在栈中的 是指向堆中数组或对象的地址,这就是为何修改引用类型总会影响到其他指向这个地址的引用变量。)
2、保存与复制的是值本身
3、使用typeof检测数据的类型
引用类型:1、保存在堆中
2、保存与复制的是指向对象的一个指针
3、使用instanceof检测数据类型
4、使用new()方法构造出的对象是引用型
在实际开发过程中,我们有时候需要判断变量的类型去做不同的逻辑处理。就会使用到typeof和instanceo操作符来判断变量类型。下面来看一下这个两个方法的区别。
二、typeof 和instanceof判断变量类型
(1)typeof 判断变量类型 typeof操作符是确定一个变量是字符串、数值、布尔值、还是undefined的最佳工具。如果一个变量是一个对象或者null,那么typeof就会返回“object”;虽然typeof在检测基本数据类型时是非常的得力的助手,但是在检测对象类型的时候用处就不大了,此时我们就需要instanceof操作符了,语法如下:result = variable instanceof constructor
如果变量是给定的引用类型那么就会返回true,否则就会返回false 所有的引用类型的值都是Object的实例,因此在检测一个引用类型值和Object的构造函数时,instanceof都会返回true,如果使用instanceof操作符检测基本类型的值,则该操作符时钟会返回false,因此基本类型不是对象。那么instanceof的原理是什么?为什么能判断 变量是否来源于某个构造函数?涉及到原型以及原型链的知识。下一节研究什么是原型以及原型链。搞懂原型和原型链后instanceof的原理就明白了。三、原型和原型链
1、原型
原型分为隐式原型(__proto__)和显式原型(prototype)。 由于所有的引用类型(数组、对象、函数)都具有对象特性。即可自由扩展属性(除了‘null')。因此浏览器为每一个可扩展的对象添加了一个__proto__属性。该属性称为隐式原型,是一个普通对象。
可以看到__proto__是一个对象,具有constructor、hansOwnProperty等属性。 函数也是引用类型,因此浏览器为其扩展了一个默认属性 prototype。叫作显式原型。也是一个普通的对象。 该对象包含了constructor和__proto__属性。隐式原型和显示原型的关系用一句话概述就是:对象的隐式原型指向构造该对象的构造函数的显式原型。 对象student是通过构造函数People实例化而来的。因此student的隐式原型(proto)与构造函数People的显示原型(prototype)完全相等。2、原型链
当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的隐式原型__proto__(即它的构造函数的prototype)中寻找。如果它的构造函数的prototype中没有该属性,那么就会通过prototype.__proto__中去寻找。以此类推如果存在该属性会直到找到该属性为止。浏览器为了防止无限循环,找到最上层就是object了(祖先),再往上找就是null,说明此时不存在该属性。这个寻找的过程会形成一条链路,就是原型链。如下图所示:
其中Foo是构造函数,f是其实例化对象。曲线__proto__形成的就是原型链。 3、原型链的应用 简单模拟jquery封装dom方法的过程。 div1是构造函数Elem的实例化对象,调用html(div1.html())方法时,首先会在div1上寻找该方法。但是该对象上并没有该方法,因此会通过div1.__proto__即Elem.prototype去寻找该方法。正好Elem.prototype上有html方法,停止寻找并执行该方法。当调用toString()方法时候还是通过同样的方式去寻找,但是Elem.prototype上也不存在该方法,于是就通过Elem.prototype.__proto__向上寻找。所有对象的构造函数是Object。所以此时会去Object.prototype上寻找toString()方法。正好该对象上存在该方法,于是停止寻找并执行该方法。