JavaScript类型检测之typeof 和 instanceof 的缺陷与优化


Posted in Javascript onJanuary 13, 2016

在javascript中,typeof 和 instanceof 是用来判断数据类型比较通用的两个方法,这篇文章的目的是通过对这两个方法介绍来分析其存在的不足并提出优化方案。

typeof

--------------------------------------------------------------------------------

typeof 返回一个表达式的数据类型的字符串,返回结果为javascript中的基本数据类型,包括:number、boolean、string、object、undefined、function等6种数据类型。

typeof 100; //number
typeof (1==1); //boolean
typeof 'onepixel'; //string
typeof {} ; //object
typeof onepixel; // undefined
typeof parseInt; // function
typeof [];//object
typeof new Date(); //object

可以看出,typeof 可以准确的判断除object以外的基础数据类型,但不能区分object类型的具体类型,比如 Array 、Date 以及自定义类。

instanceof

--------------------------------------------------------------------------------

instanceof 本意是用来判断 A 是否为 B 的实例对象,表达式为:A instanceof B,如果A是B的实例,则返回true,否则返回false。 在这里需要特别注意的是:instanceof检测的是原型,那它是怎么检测的呢,我们用一段伪代码来模拟其内部执行过程:

instanceof (A,B) = {
var L = A.__proto__;
var R = B.prototype;
if(L === R) {
//A的内部属性__proto__指向B的原型对象
return true;
}
return false;
}

从上述过程可以看出,当A的__proto__ 指向B的prototype时,就认为A就是B的实例对象,我们再来看几个例子:

[] instanceof Array; //true
{} instanceof Object;//true
new Date() instanceof Date;//true
function Person(){};
new Person() instanceof Person;
[] instanceof Object; //true
new Date() instanceof Object;//tru
new Person instanceof Object;//true

从上面的例子中,我们发现虽然instanceof能够正确判断[] 是Array的实例对象,但不能辨别 [] 不是Object的实例对象,为什么呢,这还需要从javascript的原型链说起,我们首先来分析一下[]、Array、Object 三者之间的关系,从instanceof判断能够得出:[].__proto__ ->Array.prototype, 而Array.prototype.__proto__指向了Object.prototype,Object.prototype.__proto__ 指向了null,标志着原型链的结束。(ps:关于JS原型链请阅读:浅谈javascript原型和原型链) 因此,[]、Array、Object就形成了一条原型链:

JavaScript类型检测之typeof 和 instanceof 的缺陷与优化

从原型链可以看出,[]的__proto__最终指向了Object.prototype,类似的new Date()、new Person() 也会形成这样一条原型链,因此,我们用 instanceof 也不能完全精确的判断object类的具体数据类型。

优化方案

--------------------------------------------------------------------------------

对于这个问题,在阅读jQuery源码时,发现了一个比较好的解决方案,由于源码之间存在相互调用不便于阅读和理解,因此,按照其思路进行了整理和封装,代码如下:

(function(){
var class2type = {};
var typeList = "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " );
typeList.eachEach(function(item){
class2type[ "[object " + item + "]" ] = item.toLowerCase();
}
return {
getObjType:function(obj) {
if ( obj == null ) {
return obj + "";
}
if(typeof obj === "object" || typeof obj === "function"){
class2type[ toString.call( obj ) ] || "object"
}else {
return typeof obj;
}
}
}
})()

JavaScript 中 typeof 和 instanceof 常用来判断一个变量是否为空,或者是什么类型的。但它们之间还是有区别的:

typeof

typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型。

它返回值是一个字符串,该字符串说明运算数的类型。typeof 一般只能返回如下几个结果:

number,boolean,string,function,object,undefined。我们可以使用 typeof 来获取一个变量是否存在,如 if(typeof a!="undefined"){alert("ok")},而不要去使用 if(a) 因为如果 a 不存在(未声明)则会出错,对于 Array,Null 等特殊对象使用 typeof 一律返回 object,这正是 typeof 的局限性。

网上的一个小例子:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script language="javascript" type="text/javascript">
document.write ("typeof(1): "+typeof(1)+"<br>");
document.write ("typeof(NaN): "+typeof(NaN)+"<br>");
document.write ("typeof(Number.MIN_VALUE): "+typeof(Number.MIN_VALUE)+"<br>");
document.write ("typeof(Infinity): "+typeof(Infinity)+"<br>");
document.write ("typeof(\"123\"): "+typeof("123")+"<br>");
document.write ("typeof(true): "+typeof(true)+"<br>");
document.write ("typeof(window): "+typeof(window)+"<br>");
document.write ("typeof(Array()): "+typeof(new Array())+"<br>");
document.write ("typeof(function(){}): "+typeof(function(){})+"<br>");
document.write ("typeof(document): "+typeof(document)+"<br>");
document.write ("typeof(null): "+typeof(null)+"<br>");
document.write ("typeof(eval): "+typeof(eval)+"<br>");
document.write ("typeof(Date): "+typeof(Date)+"<br>");
document.write ("typeof(sss): "+typeof(sss)+"<br>");
document.write ("typeof(undefined): "+typeof(undefined)+"<br>")
</script>
<title>javascript类型测试</title>
</head>
<body>
</body>
</html>

instanceof

instance:实例,例子

a instanceof b?alert("true"):alert("false"); //a是b的实例?真:假

instanceof 用于判断一个变量是否某个对象的实例,如 var a=new Array();alert(a instanceof Array); 会返回 true,同时 alert(a instanceof Object) 也会返回 true;这是因为 Array 是 object 的子类。再如:function test(){};var a=new test();alert(a instanceof test) 会返回
谈到 instanceof 我们要多插入一个问题,就是 function 的 arguments,我们大家也许都认为 arguments 是一个 Array,但如果使用 instaceof 去测试会发现 arguments 不是一个 Array 对象,尽管看起来很像。

另外:

测试 var a=new Array();if (a instanceof Object) alert('Y');else alert('N');

得'Y'

但 if (window instanceof Object) alert('Y');else alert('N');

得'N'

所以,这里的 instanceof 测试的 object 是指 js 语法中的 object,不是指 dom 模型对象。

使用 typeof 会有些区别

alert(typeof(window)) 会得 object

大家知道JavaScript中判断函数参数类型是用typeof还是instanceof吗?

typeof只能判断js已有的几个类型,如function,object,number。

而instanceof可以判断对象是由哪个函数实例化出来的,如:

var a=function(x){};
var b=function(x){};
var c=new a(1);
var d=new a(2);

c instanceof a为true而d instanceof b为false。

而用typeof c和typeof d的结果都是object

“判断函数参数类型”需要根据你的需求来选择用哪个。

Javascript 相关文章推荐
javascript+dom树型菜单类,希望朋友们一起进步
May 03 Javascript
js调试系列 控制台命令行API使用方法
Jun 18 Javascript
使用Jasmine和Karma对AngularJS页面程序进行测试
Mar 05 Javascript
神奇!js+CSS+DIV实现文字颜色渐变效果
Mar 16 Javascript
Vue 页面跳转不用router-link的实现代码
Apr 12 Javascript
关于Angularjs中自定义指令一些有价值的细节和技巧小结
Apr 22 Javascript
使用vue-cli(vue脚手架)快速搭建项目的方法
May 21 Javascript
vue中子组件传递数据给父组件的讲解
Jan 27 Javascript
vue 获取视频时长的实例代码
Aug 20 Javascript
JS快速实现简单计算器
Apr 08 Javascript
electron 如何将任意资源打包的方法步骤
Apr 16 Javascript
解决vue addRoutes不生效问题
Aug 04 Javascript
jquery对复选框(checkbox)的操作汇总
Jan 13 #Javascript
分享javascript计算时间差的示例代码
Mar 19 #Javascript
学习JavaScript设计模式之代理模式
Jan 12 #Javascript
基于JavaScript实现TAB标签效果
Jan 12 #Javascript
JavaScript实现瀑布流布局
Jun 28 #Javascript
轻松实现JavaScript图片切换
Jan 12 #Javascript
jQuery动画效果图片轮播特效
Jan 12 #Javascript
You might like
基于PHP遍历数组的方法汇总分析
2013/06/08 PHP
PHP时间戳格式全部汇总 (获取时间、时间戳)
2016/06/13 PHP
thinkphp框架实现数据添加和显示功能
2016/06/29 PHP
PHP进制转换实例分析(2,8,16,36,64进制至10进制相互转换)
2017/02/04 PHP
php自定义函数br2nl实现将html中br换行符转换为文本输入中换行符的方法【与函数nl2br功能相反】
2017/02/17 PHP
Thinkphp5.0框架使用模型Model的获取器、修改器、软删除数据操作示例
2019/10/11 PHP
有一段有意思的代码-javascript现实多行信息
2007/08/26 Javascript
javascript showModalDialog模态对话框使用说明
2009/12/31 Javascript
用JS写的一个TableView控件代码
2010/01/23 Javascript
ExtJs扩展之GroupPropertyGrid代码
2010/03/05 Javascript
javascript 伪数组实现方法
2010/10/11 Javascript
js 获取和设置css3 属性值的实现方法
2013/05/06 Javascript
浅析在javascript中创建对象的各种模式
2016/05/06 Javascript
微信小程序 实战程序简易新闻的制作
2017/01/09 Javascript
解决layui前端框架 form表单,table表等内置控件不显示的问题
2018/08/19 Javascript
一次Webpack配置文件的分离实战记录
2018/11/30 Javascript
vuex实现的简单购物车功能示例
2019/02/13 Javascript
通过实例讲解JS如何防抖动
2019/06/15 Javascript
python爬虫常用的模块分析
2014/08/29 Python
python检查序列seq是否含有aset中项的方法
2015/06/30 Python
Python的Django框架中的表单处理示例
2015/07/17 Python
python妙用之编码的转换详解
2017/04/21 Python
python中如何正确使用正则表达式的详细模式(Verbose mode expression)
2017/11/08 Python
Python实现GUI学生信息管理系统
2020/04/05 Python
Python测试网络连通性示例【基于ping】
2018/08/03 Python
python之pymysql模块简单应用示例代码
2019/12/16 Python
Python urllib库如何添加headers过程解析
2020/10/05 Python
CSS3改变浏览器滚动条样式
2019/01/04 HTML / CSS
Viking比利时:购买办公用品
2019/10/30 全球购物
Tomcat的缺省是多少,怎么修改
2014/04/09 面试题
《花木兰》教学反思
2014/04/09 职场文书
优秀的个人求职信范文
2014/05/09 职场文书
机械专业求职信范文
2014/07/15 职场文书
教学督导岗位职责
2015/04/10 职场文书
投标单位介绍信
2015/05/05 职场文书
帝企鹅日记观后感
2015/06/10 职场文书