Javascript 判断变量类型的陷阱 与 正确的处理方式
Javascript 由于各种各样的原因,在判断一个变量的数据类型方面一直存在着一些问题,其中最典型的问题恐怕就是 typeof null
会返回 object
了吧。因此在这里简单的总结一下判断数据类型时常见的陷阱,以及正确的处理姿势。
javascript 数据类型
数据类型
这里先谈一下 javascript 这门语言的数据类型。javascript 中有七种数据类型,其中有六种简单数据类型,一种复杂数据类型。
六种简单数据类型
- String
- Number
- Boolean
- Null
- Undefined
- Symbol (ECMAScript 6 新定义)
复杂数据类型
Object
是唯一的复杂数据类型。 Object Array Function
这些引用类型值最终都可以归结为 Object
复杂数据类型。
各种陷阱
typeof 的陷阱
typeof
是用来检测变量数据类型的操作符,对一个值使用 typeof
操作符可能会返回下列某个字符串
- "undefined" --- 如果这个值未定义
- "string" --- 如果这个值是字符串
- "boolean" --- 如果这个值是布尔类型值
- "number" --- 如果这个值是数值
- "object" --- 如果这个值是对象或者 null
- "function" --- 如果这个值是函数
1. Object 对象检测的陷阱
function isObj(obj) {
if (typeof obj === 'object') {
return 'It is object';
}
return 'It is not object';
}
这个函数的本意是想检测传入的参数是否是 Object 对象。但是这个函数其实是非常不安全的。
比如
var a = [1, 2, 3];
isObj(a); // 'It is object'
var b = null;
isObj(b); // 'It is object'
这样明显是不对的,因为 typeof []
和 typeof null
都是是会返回 'object'
的。
2. Array 对象检测的陷阱
typeof [] // 'object'
上面说到了对一个数组使用 typeof 操作符也是会返回 'object'
,因此 typeof 并不能判断数组对象的类型
instanceof 的陷阱 与 基本包装类型
1. instanceof
instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
2. 基本包装类
《Javascript》高级程序设计 第五章第六节 基本包装类型
javascript 为了方便操作基本类型值,ECMAscript 提供了3个特殊的引用类型:Boolean、Number 和 String。
每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。
var s1 = "some text";
var s2 = s1.substring(2);
上面的代码中,先创建了一个字符串保存在了变量 s1,字符串当然是基本类型值。但是在下一行中我们又调用了 s1 的方法。我们知道基本类型值不是对象,理论上它不应该拥有方法(但它们确实有方法)。其实,为了让我们实现这种直观的操作,后台已经帮助我们完成了一系列的操作。当我们在第二行代码中访问 s1 变量时,访问过程处于读取模式,而在读取模式中访问字符串时,后台都会自动完成下列处理。
- 创建 String 类型的一个实例;
- 在实例上调用指定的方法;
- 销毁这个实例。
可以将以上三个步骤想像成是执行了下列代码
var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;
3. instanceof 判断基本类型值的陷阱
上面提到基本包装类,就是为了说明 instanceof 这个陷阱
var str = 'text';
str instanceof String; // false
本来我也是想当然的认为 str instanceof String
会使 str 变量处于读取模式,自动建立基本包装类。但是根据上述代码所体现表象来看,instanceof 运算符是直接访问的变量的原始值。
因此 instanceof 并不能用来判断五种基本类型值
4. instanceof 判断 Object类型的陷阱
这里先说一下,用 instanceof 判断 Array 类型基本上是非常ok的
var arr = [1, 2, 3];
arr instanceof Array; // true
但是 instanceof 却不能安全的判断 Object 类型,因为 Array 构造函数是继承自 Object 对象的,因此在 arr 变量上是可以访问到 Object 的 prototype 属性的。如下例所示:
var arr = [1, 2, 3];
arr instanceof Object; // true
// 会返回 true ,是因为 Object 构造函数的 prototype 属性存在与 arr 这个数组实例的原型链上。
一个高效但危险的变量类型判断方法
用对象的 constructor 来判断对象类型
stack overflow 上有人做了实验,说是目前运算最快的判断变量类型的方式。
function cstor(variable) {
var cst = variable.constructor;
switch (cst) {
case Number:
return 'Number'
case String:
return 'String'
case Boolean:
return 'Boolean'
case Array:
return 'Array'
case Object:
return 'Object'
}
}
上面是一个判断变量类型的方法,工作的非常高效完美。但是用 constructor 判断变量类型有一个致命的缺陷,就是当检测 null 或者 undefined 类型的 constructor 属性时,js会报错!
也就是说下面代码会报错!
cstor(null); // 若传入 null 或者 undefined 作为参数时
// cstor 函数第一行就会报错,因为 null 和 undefined 根本就没有 constructor 属性
因此我们在利用变量的 constructor 属性来判断变量类型时,必须要先保证变量有 不会是 null 或者 undefined。
改造以上函数如下:
function cstor(variable) {
if (variable === null || variable === undefined) {
return 'Null or Undefined';
}
var cst = variable.constructor;
switch (cst) {
case Number:
return 'Number'
case String:
return 'String'
case Boolean:
return 'Boolean'
case Array:
return 'Array'
case Object:
return 'Object'
}
}
所以说使用 constructor 来判断对象类型时要无时无刻不伴随着排除 null 和 undefined 的干扰,否则就会产生致命的问题,因此本人并不推荐。
正确判断变量类型的姿势
一个万金油方法 Object.prototype.toString.call()
Object.prototype.toString.call(variable)
用这个方法来判断变量类型目前是最可靠的了,它总能返回正确的值。
该方法返回 "[object type]"
, 其中type是对象类型。
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call({}); // "[object Object]"
Object.prototype.toString.call(123); // "[object Number]"
Object.prototype.toString.call('123'); // "[object String]"
Object.prototype.toString.call(false); // "[object Boolean]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
String Boolean Number Undefined 四种基本类型的判断
除了 Null
之外的这四种基本类型值,都可以用 typeof
操作符很好的进行判断处理。
typeof 'abc' // "string"
typeof false // "boolean"
typeof 123 // "number"
typeof undefined // "undefined"
Null 类型的判断
除了 Object.prototype.toString.call(null)
之外,目前最好的方法就是用 variable === null
全等来判断了。
var a = null;
if (a === null) {
console.log('a is null');
}
// a is null
检测变量是否是一个 Array 数组
typeof []
会返回 object
因此明显是不能够用 typeof 操作符进行数组类型判断的。目前常用的方法有以下几种
1. Object.prototype.toString.call()
万金油方法是一种。
2. ECMAscript5 新增 Array.isArray()
Array.isArray([]); // true
3. instanceof 运算符
instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
因此可以检测一个对象的原型链中是否存在 Array 构造函数的 prototype 属性来判断是不是数组。
[] instanceof Array // true
检测变量是否是一个 Object 对象
typeof 和 instanceof 都不能安全的判断变量是否是 Object 对象。
目前判断变量是否是对象的最安全的方法就只有 Object.prototype.toString.call()
了。
作者博客:pspgbhu http://www.cnblogs.com/pspgbhu/
作者 Github:https://github.com/pspgbhu
欢迎转载,但请注明出处,谢谢!
Javascript 判断变量类型的陷阱 与 正确的处理方式的更多相关文章
- JavaScript判断变量类型
使用JavaScript变量时是无法判断出一个变量是0 还是“”的 这时可用typeof()来判断变量是string 还是number来区分0和“”, typeof(undefined) == 'un ...
- PHP判断变量类型和类型转换的三种方式
前言: PHP 在变量定义中不需要(不支持)明确的类型定义.变量类型是根据使用该变量的上下文所决定的.所以,在面对页码跳转.数值计算等严格的格式需求时,就要对变量进行类型转换. 举例如下: $foo ...
- JavaScript 变量克隆和判断变量类型
一.变量克隆 在js中经常会遇到将一个变量赋值给一个新的变量这种情况,这对于基本类型很容易去实现,直接通过等号赋值就可以了,对于引用类型就不能这样了.(注:像函数,正则也可以直接通过等号赋值) 这里我 ...
- JavaScript判断浏览器类型及版本
JavaScript是前端开发的主要语言,我们可以通过编写JavaScript程序来判断浏览器的类型及版本.JavaScript判断浏览器类型一般有两种办法,一种是根据各种浏览器独有的属性来分辨,另一 ...
- 使用javascript判断浏览器类型
之前在项目中遇到过要针对不同浏览器做不同的一些js或者css操作,后来某个朋友也突然问到这个问题,所以,整理了一下,在这里留个笔记,方便以后使用. 使用javascript判断浏览器类型: funct ...
- JavaScript判断对象类型及节点类型、节点名称和节点值
一.JavaScript判断对象类型 1.可以使用typeof函数判断对象类型 function checkObject1(){ var str="str"; console.lo ...
- 16. js 判断变量类型,包括ES6 新类型Symbol
相信大家在开发中遇到需要判断变量类型的问题,js变量按存储类型可分为值类型和引用类型,值类型包括Undefined.String.Number.Boolean,引用类型包括object.Array.F ...
- php判断变量类型
php判断变量类型 一.总结 一句话总结: gettype()函数:gettype(1);返回的是integer is_array():is系列函数 1.PHP empty.isset.isnull的 ...
- JavaScript判断图片是否加载完成的三种方式
JavaScript判断图片是否加载完成的三种方式 有时需要获取图片的尺寸,这需要在图片加载完成以后才可以.有三种方式实现,下面一一介绍. 一.load事件 1 2 3 4 5 6 7 8 9 10 ...
随机推荐
- (中级篇 NettyNIO编解码开发)第七章-java序列化
相信大多数Java程序员接触到的第一种序列化或者编解码技术就是.Java的默认序列化,只需要序列化的POJO对象实现java.io.Serializable接口,根据实际情况生成序列ID,这个类就能够 ...
- JavaScript基础(.....持续待更)
javascript热身 一.你知道,为什么JavaScript非常值得我们学习吗? 1. 所有主流浏览器都支持JavaScript. 2. 目前,全世界大部分网页都使用JavaScript. 3. ...
- iOS开发之 Lottie -- 炫酷的动效
动效在软件开发中非常常见,炫酷的动画能提升应用的B格,然而由设计师的设计转化成程序猿GG的代码是个非常"痛苦"的过程.对于复杂动画,可能要花费很多时间去研究和实现.Lottie 的 ...
- 1.Java第一课:初识java
今天也算是正式地开始学习Java了,一天学的不是太多,旨在入门了解Java.还好现在学的都是基础,也能赶得上进度,希望以后能一直保持这种精神状态坚持学下去.下面就简单来说说今天所学的内容吧. 1计算机 ...
- python——快速找出两个电子表中数据的差异
最近刚接触python,找点小任务来练练手,希望自己在实践中不断的锻炼自己解决问题的能力. 公司里会有这样的场景:有一张电子表格的内容由两三个部门或者更多的部门用到,这些员工会在维护这些表格中不定期的 ...
- Outlook 客户端无法通过 MAPI over HTTP 连接
随着Exchange 版本更新升级,是否进行验证客户端建立MapiHttp连接所需的服务器设置已正确配置.即使服务器,负载均衡器和反向代理的所有设置都正确,您可能会遇到连接到Exchange Serv ...
- VMware 创建多台Linux机器并配置IP
1.查看并分配虚拟网络 我们首先要知道 VMware 三种网络模式的区别. ①.Bridged(桥接模式):就是将主机网卡与虚拟机虚拟的网卡利用虚拟网桥进行通信.在桥接的作用下,类似于把物理主机虚拟为 ...
- ANDROID 开发,安装离线安装包的下载地址及安装方法。
前言: 建议采用离线安装的方法安装SDK包,在线的方式实在是.....多了不解释. 下面说一下离线安装的方法: 1.下载地址:http://pan.baidu.com/s/1sjuJwYD#path= ...
- 第2章 系统用户/组管理(2) su和sudo
本文目录: 2.1 su 2.2 sudo 2.2.1 /etc/sudoers文件 2.2.2 sudo和sudoedit命令 2.1 su 切换用户或以指定用户运行命令. 使用su可以指定运行命令 ...
- H5拖拽 构造拖拽及缩放 pdf展示
前言: 协助项目需要实现一个签名的功能. 功能说明:1.有文本签名和头像签名.2.头像签名需要实现可拖拽功能.3.需要展示的是pdf的文件并需要获取签名位于pdf文件的相对位置. 功能一:实现拖拽 思 ...