资讯专栏INFORMATION COLUMN

细数判断数据类型的各种方法

hoohack / 2960人阅读

摘要:可用于判断多种数据类型基本数据类型和内置对象,然而对于一些自定义构造函数生成的对象就不能进行判断了。判断是不是所有数据类型中,只有不等于它本身判断数组的方法除了上文提到的三种方法可判断外,还有一个构造函数自带的方法可判断。

数据类型的分类

要想判断数据类型,首先要知道数据类型的分类。数据类型分为基本数据类型和引用数据类型。

基本数据类型

基本数据类型有 种,ES6中新加了第 种基本数据类型——Symbol 类型。

数值 (number): 整数和小数。

字符串 (string): 文本

布尔值 (boolean):true 和 false 。

undefined: 表示‘未定义’或不存在。一般情况下变量在声明后未赋值前都是undefined。

null: 空值。

symbol: ES6 引入的新原始数据类型,表示独一无二的值。

引用数据类型

引用类型数据也会统称为对象,即广义的对象,通常除了基本数据类型的其它数据都属于引用类型数据。

对象 (object): 狭义的对象,{key1:value1, key2:value2,...}

数组 (array): [value1,value2,...]

函数 (function)

日期 (date)

正则表达式 (RegExp)

......

数据类型综合判断的各种方法 typeof 运算符

typeof 返回字符串,numberstringbooleansymbolundefinedfunction,所有其它的引用类型数据都返回 objectnull 也返回 object

typeof 666          // "number"
typeof "dora"       // "string"
typeof true         // "boolean"
typeof Symbol()     // "symbol"
typeof undefined    // "undefined"
typeof null         // "object"
typeof function(){} // "function"
typeof []           // "object"
typeof /dora/       // "object"
优点

可利用判断 undefined 来检查一个没有声明的变量,而不报错。实际编程中,这个特点通常用在判断语句中。

// 错误的写法
if (v) {
  // ...
}
// ReferenceError: v is not defined

// 正确的写法
if (typeof v === "undefined") {
  // 这种写法在 v 没有声明的时候不会报错。
}

注意

ES6中引入了 let 之后,这个方法也不是万能的了。当变量在代码块内用 let 声明的时候,会形成“暂时性死区”(temporal dead zone,简称 TDZ),此时这个方法就没用了,typeof 还是会报错。

typeof x; // ReferenceError
let x;
缺点

不能准确的判断引用类型数据的具体类型,除了函数外,其余的都是返回object

typeof {}     // "object"
typeof []     // "object"

此时,在需要判断数组或者对象时,就不适用了。

Object.prototype.toString.call(value)

Object.prototype.toString() 方法返回对象的类型字符串,因此可以用来判断一个值的类型。

var obj = {};
obj.toString()  // "[object Object]"

上面代码调用空对象的toString方法,结果返回一个字符串 object Object,其中第二个Object表示该值的 构造函数

由于实例对象可能会自定义toString方法,覆盖掉 Object.prototype.toString方法,所以为了得到类型字符串,最好直接使用Object.prototype.toString方法。通过函数的call方法,可以在任意值上调用这个方法,帮助我们判断这个值的类型。

Object.prototype.toString.call(value)

上面代码表示对value这个值调用Object.prototype.toString方法。

返回值

不同数据类型的Object.prototype.toString方法返回值如下:

数值:返回 [object Number]

字符串:返回 [object String]

布尔值:返回 [object Boolean]

undefined:返回 [object Undefined]

null:返回 [object Null]

Symbol类型:返回 [object Symbol]

数组:返回 [object Array]

arguments 对象:返回 [object Arguments]

函数:返回 [object Function]

Error 对象:返回 [object Error]

Date 对象:返回 [object Date]

RegExp 对象:返回 [object RegExp]

其他对象:返回 [object Object]

Object.prototype.toString.call(2)          // "[object Number]"
Object.prototype.toString.call("")         // "[object String]"
Object.prototype.toString.call(true)       // "[object Boolean]"
Object.prototype.toString.call(undefined)  // "[object Undefined]"
Object.prototype.toString.call(null)       // "[object Null]"
Object.prototype.toString.call(Symbol())   // "[object Symbol]"
Object.prototype.toString.call(Math)       // "[object Math]"
Object.prototype.toString.call({})         // "[object Object]"
Object.prototype.toString.call([])         // "[object Array]"
封装实用函数

利用这个特性,可以封装一个比typeof运算符更准确的类型判断函数。

var type = function (o){
  var s = Object.prototype.toString.call(o);
  return s.match(/[object (.*?)]/)[1].toLowerCase();
};

type({});           // "object"
type([]);           // "array"
type(5);            // "number"
type(null);         // "null"
type();             // "undefined"
type(/dora/);       // "regexp"
type(new Date());   // "date"

在上面这个type函数的基础上,还可以加上专门判断某种类型数据的方法。

var dataArr = ["Null", "Undefined", "Object", "Array", "String", "Number", "Boolean", "Function", "RegExp"];
  dataArr.forEach(function (t) {
    type["is" + t] = function (o) {
      return type(o) === t.toLowerCase();
    };
  });

  type.isObject({});    // true
  type.isNumber(NaN);   // true
  type.isRegExp(/abc/); // true
instanceof 运算符

instanceof 运算符返回一个布尔值,表示对象是否为某个构造函数的实例。

function People(){}
var person = new People();
person instanceof People // true
判断原理

遍访对象的原型链上的每个原型对象,如果遍访到这个原型对象,是某个构造函数的prototype,那么就认为对象是这个构造函数的实例,返回true。因此同一个实例对象,可能会对多个构造函数都返回true,因为继承的子类实例也是父类的实例。

var d = new Date();
d instanceof Date    // true
d instanceof Object  // true

特殊情况

有一种特殊情况,就是左边对象的原型链上,只有null对象。这时,instanceof判断会失真。

var obj = Object.create(null);
typeof obj              // "object"
obj instanceof Object   // false

上面代码中,Object.create(null)返回一个新对象obj,它的原型是null。右边的构造函数Objectprototype属性,不在左边的原型链上,因此instanceof就认为obj不是Object的实例。

只要一个对象的原型不是nullinstanceof运算符的判断就不会失真。

类型判断

instanceof运算符只能用于对象,不适用原始类型的值,且对于undefinednullinstanceof运算符总是返回false

"hello" instanceof String      // false
undefined instanceof Object    // false
null instanceof Object         // false

可用于对象,无论是 JavaScript 内置对象或是自定义构造函数生成的对象,都可进行判断。

[] instanceof Array                   // true
({}) instanceof Object                // true
(function(){}) instanceof Function    // true
/a/ instanceof RegExp                 // true
new Date() instanceof Date            // true
person instanceof People              // true

constructor 属性

prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承。因此,正常情况下,所有对象实例都有一个constructor属性,属性值指向构造此对象实例的构造函数。

[].constructor === Array       // true
[].constructor === Object      // false
window.constructor === Window  //true
name属性

如果不能确定对象实例的constructor属性是什么函数,可通过函数的name属性,从实例得到构造函数的名称。

function Foo() {}
var f = new Foo();
f.constructor.name // "Foo"
类型判断

基本数据类型

nullundefined是无效的对象,因此是不会有constructor存在的,这两种类型的数据需要通过typeof来判断。

numberstringboolean三种数据类型有对应的NumberStringBoolean三个原生对象(包装对象)。因此,也可用 constructor进行判断。symbol类型也可判断。

(333).constructor.name    // "Number"
"".constructor.name       // "String"
false.constructor.name    // "Boolean"
Symbol().constructor.name // "Symbol"

引用数据类型

JavaScript 内置对象或是自定义构造函数生成的对象,都可进行判断。

new Date().constructor === Date   //true
[].constructor === Array          //true

function F(){};
var f = new F();
f.constructor === F          // true
f.constructor === Object     // false
不稳定因素

constructor属性表示原型对象与构造函数之间的关联关系,有时开发者会因业务关系重写prototype,原有的constructor会丢失,若没有同时修改constructor属性,引用的时候就会出错,constructor会默认为Object

function Person(name) {
  this.name = name;
}

Person.prototype.constructor === Person // true

Person.prototype = {
  method: function () {}
};

Person.prototype.constructor === Person // false
Person.prototype.constructor === Object // true

因此,修改原型对象时,一般要同时修改constructor属性的指向,或者只在原型对象上添加方法,不要重写prototype

总结

typeof
typeof 可用来判断基本数据类型和函数,不可以对引用数据类型进行具体的判断。

Object.prototype.toString.call(value)
Object.prototype.toString.call(value) 可用于判断多种数据类型:基本数据类型和 JavaScript 内置对象,然而对于一些自定义构造函数生成的对象就不能进行判断了。

instanceof
instanceof 运算符不适用判断原始类型的值,只能用于判断对象,无论是 JavaScript 内置对象或是自定义构造函数生成的对象,都可进行判断。然而由于继承的存在,instanceof 判断也不完全准确,只能用来判断两个对象是否属于原型链的关系,而不一定能获取对象的具体类型。

constructor
constructor 属性可准确的判断对象实例是由哪个构造函数生成的,但自定义构造函数生成的对象,往往会因为重写prototype造成constructor属性指向不准确,因此使用的时候也要注意一下。

一些其它的具体类型判断 判断变量是否为对象(引用类型)

Object(x)的参数为对象时,总是返回该对象,不做转换;当参数为原始类型时,会转换为对应的包装对象的实例,参数为空或者undefined或者null时,返回一个空对象。

function isObject(value) {
  return value === Object(value);
}
isObject([]); // true
isObject(true); // false
判断是不是 NaN

所有数据类型中,只有NaN不等于它本身

function isNaN(value) {
  return value !== value;
}
isNaN(NaN);  // true
判断数组的方法 Array.isArray()

除了上文提到的三种方法(toString()instanceofconstructor)可判断外,还有一个Array构造函数自带的方法isArray()
可判断。

Array.isArray(x)

如果x是数组,则为true; 否则为false

Array.isArray([]);                // true
Array.isArray(new Array());       // true
Array.isArray(Array.prototype);   // true  鲜为人知的事实:其实 Array.prototype 也是一个数组。

使用之前需检测一下兼容性,对于不兼容的浏览器可使用下面的代码创建该方法。

if (!Array.isArray) {
  Array.isArray = function(arg) {
    return Object.prototype.toString.call(arg) === "[object Array]";
  };
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98922.html

相关文章

  • 细数 JavaScript 实用黑科技(一)

    摘要:小汪经过实践得出以下用途。空数组的类型也是,这表示在内部,数组本质上只是一种特殊的对象。调用函数时,某个参数未设置任何值,这时就可以传入,表示该参数为空。前端还是很有未来的下节内容细数实用黑科技二。 showImg(https://segmentfault.com/img/remote/1460000016507838); 前言 只有深入学精一门语言,学其他语言才能更好地举一反三,触类...

    ConardLi 评论0 收藏0
  • 细数你不得不知容器安全工具

    摘要:你首先需要了解的安全工具之一就是。是另一个可为进行安全漏洞扫描的工具。和相似,是的安全审核工具。和其他容器安全工具不同,使用创建自定义配置文件非常容易。月日,北京海航万豪酒店,容器技术大会即将举行。 网络安全问题的重要性大概毋庸置疑,最近无数关于恶意软件和安全漏洞的消息已充分证明了这一点。 假如你要管理一个Docker环境,并希望帮助自己的公司或用户在下一个大漏洞来临时避免遇到麻烦,那...

    刘德刚 评论0 收藏0
  • 细数你不得不知容器安全工具

    摘要:你首先需要了解的安全工具之一就是。是另一个可为进行安全漏洞扫描的工具。和相似,是的安全审核工具。和其他容器安全工具不同,使用创建自定义配置文件非常容易。月日,北京海航万豪酒店,容器技术大会即将举行。 网络安全问题的重要性大概毋庸置疑,最近无数关于恶意软件和安全漏洞的消息已充分证明了这一点。 假如你要管理一个Docker环境,并希望帮助自己的公司或用户在下一个大漏洞来临时避免遇到麻烦,那...

    zhoutk 评论0 收藏0
  • 细数JavaScript中那些神乎其神技巧

    摘要:闲来无事,整理一下中那些神乎其神的技巧,假装大牛的样子字符串转换为数字同样可用于日期转换为数值数值向下取整字符串转换为数值并取整谢谢开始学习前端指正,该取整直接去除小数点后数字,仅对正数有效函数设置默认值为时最后都得到变量值交换使用 闲来无事,整理一下JavaScript中那些神乎其神的技巧,假装大牛的样子 1. 字符串转换为数字 var a = 123; consol...

    Sleepy 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<