一、前言

类型判断有时候真的头疼,但是一旦熟练使用就会觉得不过如此。初级的,会判断数字和字符串。中级的,会判断数组和对象。进阶的,会判断日期,正则,错误类型。高级的,会判断plainObject,空对象,window对象等等。

基本类型:String、Number、Boolean、Symbol、Undefined、Null

引用类型:Object

基本类型也称为简单类型,由于其占据空间固定,是简单的数据段,为了便于提升变量查询速度,将其存储在栈中,即按值访问。

引用类型也称为复杂类型,由于其值的大小会改变,所以不能将其存放在栈中,否则会降低变量查询速度,因此,其值存储在堆(heap)中,而存储在变量处的值,是一个指针,指向存储对象的内存处,即按址访问。引用类型除 Object 外,还包括 Function 、Array、RegExp、Date 等等。

鉴于 ECMAScript 是松散类型的,因此需要有一种手段来检测给定变量的数据类型。对于这个问题,JavaScript 也提供了多种方法,但遗憾的是,不同的方法得到的结果参差不齐。

二、typeof

typeof是最经常用到的判断类型的。

typeof('saucxs')    //'string'
typeof 'saucxs'   //'string'
typeof function(){console.log('saucxs')}   //'function'
typeof ['saucxs','songEagle',1,2,'a']    //'object'
typeof {name: 'saucxs'}    //'object'
typeof 1   //'number'
typeof undefined     //'undefined'
typeof null    //'object'
typeof /^\d/   //'object'
typeof Symbol   // 'function'

其实,typeof是一个运算符,和加减乘除类似,这就是为啥可以这样写 typeof 'saucxs'。

在《JavaScript权威指南》中对typeof的介绍:typeof是一元操作符,放在单个操作数的前面,操作数可以是任意类型。返回值表示操作数的类型的一个字符串。

JavaScript中一共有6中基本数据类型:string,number,boolean,null,undefined,symbol,一种对象类型:object。

分别对应的typeof的值,结果不是一一对应的,分别:string,number,boolean,object,undefined,function,对象类型:object。

注意:typeof 可以检测函数类型

但是在object下还有很多细分内部属性:Array,Function,Date,RegExp,Error等。

var date = new Date();
var error = new Error();
console.log(typeof date); // object
console.log(typeof error); // object

所以还需要更好的区分。

三、instanceof

使用instanceof的前提条件:object instanceof constructor。object--要检测的对象。constructor--某个构造函数。说明使用这个instanceof必须是用来检测对象的的类型,不能检测其他类型。

A instanceof B用来判断A是否为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 Array([1,43,6]) instanceof Array    // true
new Array([1,43,6]) instanceof Object   // true{} instanceof Object   // 原型上没有定义  Uncaught SyntaxError: Unexpected token instanceof
({})  instanceof Object;   //true
Object.create({'name': 'saucxs'}) instanceof  Object   //true
Object.create(null) instanceof  Object    //false  一种创建对象的方法,这种方法创建的对象不是Object的一个实例new Date() instanceof Date   //true
new Date() instanceof Object   //true'saucxs' instanceof Object   //false
'saucxs' instanceof String  //false
new String("saucxs") instanceof Object  //true
new String("saucxs") instanceof String  //true1 instanceof Object   //false
1 instanceof Number   //false
new Number(1) instanceof Object  //true
new Number(1) instanceof Number  //truetrue instanceof Object   //false
true instanceof Boolean   //false
new Boolean(true) instanceof Object  //true
new Boolean(true) instanceof Boolean   //truenull instanceof Object    //false
undefined instanceof Object  //false
Symbol() instanceof Symbol   //false

注意:1、new Date对象既属于Object,又属于Date。(他们是由Object类派生出来的)。

2、用字面量创建的数组或者构造函数创建的数组,既属于Object,又属于Array。

3、用对象字面量创建的对象object 会报错, {} instanceof Object;使用构造函数创建的对象属于Object。

4、用字面量的创建的字符串,数字,布尔,既不属于Object,也不属于各自类型;只有使用构造函数创建的字符串,数字,布尔,既属于Object,又属于各自的类型。

发现[],构造函数创建的Date,Object,String,Number,Boolean。既属于自身,又属于Object。

举个例子,[], Array, Object的关系:

从 instanceof 能够判断出 [ ].proto 指向 Array.prototype,而 Array.prototype.proto 又指向了Object.prototype,最终 Object.prototype.proto 指向了null,标志着原型链的结束。因此,[]、Array、Object 就在内部形成了一条原型链:

从原型链可以看出,[] 的 proto 直接指向Array.prototype,间接指向 Object.prototype,所以按照 instanceof 的判断规则,[] 就是Object的实例。依次类推,类似的 new Date()、new Person() 也会形成一条对应的原型链 。因此,instanceof 只能判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。

存在的问题:

它假定只有一个全局执行环境。如果网页中包含多个框架,那实际上就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的构造函数。如果你从一个框架向另一个框架传入一个数组,那么传入的数组与在第二个框架中原生创建的数组分别具有各自不同的构造函数。

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[0].Array;
var arr = new xArray(1,2,3); // [1,2,3]
arr instanceof Array; // false

针对数组问题,ES5 提供了 Array.isArray() 方法 。该方法用以确认某个对象本身是否为 Array 类型。

if (Array.isArray(value)){//对数组执行某些操作
}

Array.isArray() 本质上检测的是对象的 [[Class]] 值,[[Class]] 是对象的一个内部属性,里面包含了对象的类型信息,其格式为 [object Xxx] ,Xxx 就是对应的具体类型 。对于数组而言,[[Class]] 的值就是 [object Array] 。

四、constructor

定义一个构造函数Func(),JS引擎会给Func添加prototype原型,然后再给prototype上添加一个constructor属性,并且指向Func的引用。

实例化一个函数func,var func = new Func()。此时Func原型上的constructor传递到func上,因此func.constructor === Func。

Func利用原型对象上的constructor引用自身,当Func作为构造函数来创建实例化对象时,原型上的constructor就会遗传到新创建的对象上。从原型链角度讲,构造函数Func就是新对象的func的类型。这样存在的意义就是新对象产生之后,可以追踪数据类型。

JavaScript 中的内置对象在内部构建时也是这样做的:

'saucxs'.constructor === String    //true
new String('saucxs').constructor === String   //true
[].constructor === Array     //true
new Array([12,56]).constructor === Array     //truenew Number(12).constructor === Number    //true
new Function(console.log('saucxs')).constructor === Function     //true
new Date().constructor === Date     //true
new Error().constructor === Error     //truewindow.constructor === Window   //true
document.constructor === HTMLDocument  //true

注意:

(1) null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。

(2)函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object

为什么变成了 Object?

因为 prototype 被重新赋值的是一个 { }, { } 是 new Object() 的字面量,因此 new Object() 会将 Object 原型上的 constructor 传递给 { },也就是 Object 本身。

因此,为了规范开发,在重写对象原型时一般都需要重新给 constructor 赋值,以保证对象实例的类型不被篡改。

五、Object.prototype.toString

toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为字符串 [object xxx] ,其中 xxx 就是对象的类型。

这个方法到底是个啥?可以 先看ES5 规范地址:es5.github.io/#x15.2.4.2

toString方法被调用的时候,会按照这个步骤执行:

(1)如果this的值是undefined,就返回[object Undefined];

(2)如果this的值是null,就返回[object Null];

(3)让O成为ToObject(this)的结果;

(4)让class成为O的内部属性[[class]]的值;

(5)最后返回由"[object" 和 class 和 "]"三个部分组成的字符串。

一句话就是:调用Object.prototype.toString 会返回一个"[object" 和 class 和 "]"组成的字符串,而class要判断对象的内部属性。

console.log(Object.prototype.toString.call(undefined)) // '[object Undefined]'
console.log(Object.prototype.toString.call(null)) // '[object Null]'
console.log(Object.prototype.toString.call(Window))  // '[object Function]'var date = new Date();
console.log(Object.prototype.toString.call(date)) // '[object Date]'
console.log(Object.prototype.toString.call(Symbol)) // '[object Function]'

注意:通过call改变this的指向。

所以这个class的值是识别对象类型的关键,所以使用Object.prototype.toString方法识别出更多的类型,可以识别出至少11种类型

var number = 1;          // [object Number]
var string = '123';      // [object String]
var boolean = true;      // [object Boolean]
var und = undefined;     // [object Undefined]
var nul = null;          // [object Null]
var obj = {a: 1}         // [object Object]
var array = [1, 2, 3];   // [object Array]
var date = new Date();   // [object Date]
var error = new Error(); // [object Error]
var reg = /a/g;          // [object RegExp]
var func = function a(){}; // [object Function]
Math    //[object Math]
JSON  //[object JSON]

注意:

1、其实Math对象和JSON对象,并不会去判断;

2、Math对象并不像Date和String那样对象的类,没有构造函数Math(), Math.sin()这样的只是函数,不是某一个对象的方法。

六、研究jquery的type API

使用Object.prototype.toString这个方法,判断各种类型就比较轻松了,参考了jquery的源码的type部分:

function type(obj) {// 一箭双雕if (obj == null) {return obj + "";}return typeof obj === "object" || typeof obj === "function" ?class2type[Object.prototype.toString.call(obj)] || "object" :typeof obj;
}

其中class2type部分

var class2type = {};// 生成class2type映射
"Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) {class2type["[object " + item + "]"] = item.toLowerCase();
})

使用:

type(1);   //'number'
type('123456');  //'string'
type(true);      //boolean
type(undefined);    //undefined
type(null);     //'null'
type({name: 'saucxs'});   //'object'
type([1,2,'saucxs',3,4]);   //'array'
type(new Date());    // 'date'
type(new Error());   //'error'
type(/^\d/);    //'regexp'
type(function(){console.log('saucxs')});   //'function'
type(Symbol);   //'function'

这就非常完美的实现了,对我们日常需要类型的判断。

实现了判断日期,正则,错误类型等。

如果还需要判断比较复杂的,比如:空对象,window对象,类数组对象等等。

七、空对象EmptyObject

jQuery提供了 isEmptyObject 方法来判断是否是空对象

function isEmptyObject( obj ) {var name;for ( name in obj ) {return false;}return true;
}

思路:判断空对象就是判断是是否有属性值,for循环一旦执行,就说明有属性,有属性返回false。

console.log(isEmptyObject({})); // true
console.log(isEmptyObject([])); // true
console.log(isEmptyObject(null)); // true
console.log(isEmptyObject(undefined)); // true
console.log(isEmptyObject(123)); // true
console.log(isEmptyObject('')); // true
console.log(isEmptyObject(true)); // true

这个判断主要用来区别 {} 和 {name: 'saucxs'} 就行。

注意点:(1)for in 是ES6的属性,这个会遍历原型上的属性。(2)使用Object.keys(obj)是ES5的属性,不会遍历原型上的属性

八、window对象

window对象是客户端js的全局对象,他有一个window属性指向自身。根据这个特性判断是否为window对象。

function isWindow(obj){return obj != null && obj ===obj.window;
}

注意:一个普通对象拥有 window 属性,并且指向自身。比如这个:

function isWindow( obj ) {return obj != null && obj === obj.window;
}
let fakeWindow = {}
fakeWindow.window = fakeWindow
isWindow(fakeWindow) // true

是不是可以这么修改呢?

function isWindow(obj) {return !!(window && obj === window)
}

九、类数组对象

如果对类数组没有概念,举个例子:

1、数组和类数组

var arr = [,,3];

对应的类数组是

var arrLike = {2: 3,length: 3
}

看jquery的源码

function isArrayLike(obj) {// obj 必须有 length属性var length = !!obj && "length" in obj && obj.length;var typeRes = type(obj);// 排除掉函数和 Window 对象if (typeRes === "function" || isWindow(obj)) {return false;}return typeRes === "array" || length === 0 ||typeof length === "number" && length > 0 && (length - 1) in obj;
}

所以如果 isArrayLike 返回true,至少要满足三个条件之一:

(1)是数组

(2)长度为 0

(3)lengths 属性是大于 0 的数字类型,并且obj[length - 1]必须存在

第三个条件:数组中用逗号直接跳过的时候,我们认为该元素是不存在的,类数组对象中也就不用写这个元素,但是最后一个元素是一定要写的,要不然 length 的长度就不会是最后一个元素的 key 值加 1。比如数组可以这样写

var arr = [1,,];
console.log(arr.length) // 2

改写成类数组

var arrLike = {0: 1,length: 1
}

所以符合条件的类数组对象是一定存在最后一个元素的!

十、判断是不是dom元素

isElement 判断是不是 DOM 元素。

isElement = function(obj) {return !!(obj && obj.nodeType === 1);
};

十一、总结

判断类型主要时四个方法:(1)typeof;(2)instanceof;(3)constructor;(4)Object.prototype.toString()。

从基本的六种类型判断,可以使用typeof,如果涉及到对象的内部类型时候;还可以使用instanceof,检测对象原型的;还可以使用constructor属性是不是指向他们构造函数;需要使用Object.prototype.toString(),如果需要判断空对象,可以使用ES6 的 for in 来判断,用window属性指向自身来判断是不是window对象。以及类数组对象的判断,以及判断是不是dom元素的判断。

JavaScript系列--类型判断的4种基本方法,研究jquery的type方法,空对象的检测方法,类数组对象...相关推荐

  1. JavaScript类数组对象参考

    JavaScript和DOM中有很多类数组对象,它们有以下特点 1.有length属性 2.可以使用[]通过下标访问 3.部分类数组对象使用[]访问成员时不只可以使用下标,还可以使用id或name 4 ...

  2. 详解JavaScript变量类型判断及domReady原理 写得很好

    原文:详解JavaScript变量类型判断及domReady原理 我们知道,在开发JavaScript时候,经常要判断JavaScript变量类型,此 JavaScript教程 详细介绍JS变量的判断 ...

  3. js基础(数组)--数组类型、类数组对象、作为数组的字符串

    1.数组类型 我们到处都可以看见数组是具有特殊行为的对象.给定一个未知的对象,判定它是否为数组通常非常 有用.在ECMAScript 5中,可以使用Array.isArray()函数来做这件事情:Ar ...

  4. JavaScript 的怪癖 8:“类数组对象”

    原文: JavaScript quirk 8 array-like objects 译者: Malcolm Yu 此文是 javascript 的 12 个怪癖(quirks) 系列的第八篇. Jav ...

  5. 【JavaScript】类数组对象

    欢迎学习交流!!! 持续更新中- 文章目录 类数组对象 arguments 类数组对象 理解:是JS中一种特殊的对象.本质上来说对象是满足了一定条件的数组,类数组的使用目的在于使得一个对象既有数组的特 ...

  6. java判断类型_Java中类型判断的几种方式 - 码农小胖哥 - 博客园

    1. 前言 在Java这种强类型语言中类型转换.类型判断是经常遇到的.今天就细数一下Java中类型判断的方法方式. 2. instanceof instanceof是Java的一个运算符,用来判断一个 ...

  7. java 判断类型_Java中类型判断的几种方式

    在Java这种强类型语言中类型转换.类型判断是经常遇到的.今天就细数一下Java中类型判断的方法方式.拉勾IT课小编为大家提供java种类型判断方式. instanceof instanceof是Ja ...

  8. Java中类型判断的几种方式

    前言 在Java这种强类型语言中类型转换.类型判断是经常遇到的.今天就细数一下Java中类型判断的方法方式. 2. instanceof instanceof是Java的一个运算符,用来判断一个对象是 ...

  9. java判断类型_Java中类型判断的几种方式

    1. 前言 在Java这种强类型语言中类型转换.类型判断是经常遇到的.今天就细数一下Java中类型判断的方法方式. 2. instanceof instanceof是Java的一个运算符,用来判断一个 ...

  10. 一种使用可满足性模数理论模型检查可编程逻辑控制器系统的恶意软件检测方法

    A malware detection method using satisfiability modulo theory model checking for the programmable lo ...

最新文章

  1. 如何配置IntelliJ IDEA发布JavaEE项目?
  2. 廖雪峰说python_廖雪峰官网Python部分的疑问及解决
  3. php中tags,php中strip_tags()函数的用法举例
  4. Java并发编程-volatile关键字介绍
  5. 关于单片机串口发送和接收的问题
  6. Linux安装MariaDB(Mysql)和简单配置
  7. php 注入是什么意思,如何理解ThinkPHP框架里的依赖注入?
  8. 有几百万的房子,也吃不起西贝,感觉像在交税…….
  9. SqlServer日期时间格式转换
  10. 17个机器学习的常用算法!
  11. 1000套电子物联网专业毕业设计和电赛设计资料822份
  12. 计算机丢失boost,Win7系统安装后出现无法开启readyboost怎么办?
  13. QCalendarWidget 日历控件
  14. c语言字符串内容匹配,C语言字符串匹配函数
  15. android 台球开源,森林里的台球赛 Android新游《丛林撞球》
  16. 中国居民身份证、通行证(含香港、澳门、台湾)资料整理,含编码规则
  17. OTU/ASV/Feature tabel 表格 过滤 相对丰度 微生物
  18. xaxis python_python-平日名称中的xaxis
  19. 如何读书:实用性阅读指南
  20. 关于前端上传文件到后台,文件大小超出限制,导致上传失败的解决办法。

热门文章

  1. poj1270_toposort+回溯
  2. centos 7安装搭建confluence-wiki
  3. 多进程——守护进程例子
  4. 树形dp贪吃的九头龙(vijos1523)
  5. 安装新版xampp后apache无法启动提示:Apache Service detected with wrong path解决方案
  6. SQL window身份登陆 SQL server不能登陆
  7. QTP自动化测试—用户登录
  8. jquery 插件 thickbox窗口 第一个控件获得焦点(解决第二次弹出窗口,文本不能输入数据)...
  9. 八、异常、java笔记
  10. 手机验证码免费10条\java、C#、html....