资讯专栏INFORMATION COLUMN

杂谈数据类型获取

newsning / 1885人阅读

摘要:如果项目中需要频繁的进行数据类型的判断与获取可以考虑进行封装,简单的处理与已足够。

前言

在js中数据我们经常需要判断或者获取数据类型,大部分时候我们都是通过type加instanceof来组合判断数据类型来实现,大部分代码中对于数据类型的获取处理都比较丑陋,前段时间看了一下Q的源代码中对数据类型的判断与获取处理,看起来相当简洁也比较好用,这篇文章来进行一下发散。

typeof

在js中我们判断数据类型经常会用到typeof,比如判断一个数据是否是一个数字类型

var n = 99;
typeof(n) === "number";    // true

这么做有一个缺点,typeof只能判断js中的基础数据类型undefined、String、Number、Boolean、Object。如果需要判断一个数据是不是Array类型,这个时候instanceof就派上用场了。

instanceof

官方对于instanceof说明: 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性(翻译成人话:判断对象指向构造函数名称是否与构造函数名一致),如图:

判断一个数据是否是时间类型,一般我们都这样写:

var list = [];
list instanceof Date;    // false

instanceof有一个缺点,只能针对对象类型的数据进行处理,因为只有对象中才包含原型链prototype,当然平常我们用到的function数据类型也是对象的一种,还是一图解千言,看一下js中的数据类型大概明了。

判断null的数据类型

在js中null也是Object中的一个子类型(关于null,可以看这篇文章),但是我们不能通过instanceof去获取,因为null中并没有原型链prototype,于是我们有了这样的代码:

var str = "null";
str === null;    // false
基础版本获取数据类型

当我们并不知道数据类型,但是需要获这个数据的类型时,大部分童鞋的代码里面都是这样写的:

classString(obj) {
    if (obj && (obj.__proto__ || obj.prototype)) {
        if (obj instanceof Array) {
            return "array";
        }
        if (obj instanceof Function) {
           return "function";
        } 
        // 所有obj的衍生数据都判断一遍 ...
    } else if (obj === null) {
        return "null";    // 返回字符串
    } else {
        return typeof(obj);
    }
}

这样的代码很繁杂,这么多的”if else“(俗称面条代码),既不美观,也不实用。

升级版本获取数据类型
function classString(obj) {
    return ({}).toString.call(obj);
}
classString(null);    // [object Null]
classString("string");    // [object String]
classString(function(){});    // [object Function]
classString(new Date());    // [object Function]

有两个关键方法:一个是call,另一个是Object.prototype.toString方法进行处理。

先看call方法简短描述:

fun.call(this, arg1, arg2, ...)
call: 调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)

再看一下关于call参数说明:

在fun函数运行时指定的this值。需要注意的是,指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于非严格模式下,则指定为null和undefined的this值会自动指向全局对象,同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。

只有当this不存在上下文的时候,this才会指向全局对象(浏览器中就是window对象)。

”包装对象“,并不是一种数据类型,原始数据类型中:字符串、数字、布尔值可以转换成相应的Number、String、Boolean对应的原生对象(注意是对象,不是值),具体在call中的表现形式如下(左边等价于右边):

再举个栗子?:

999 instanceof Number;    // false
new Number(999) instanceof Number;    // true

关于Object toString方法的简短说明:

默认情况下,toString()方法被每个Object对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 "[object type]",其中type是对象的类型。

这里的type并不是js5中基础数据类型相关的type,而是当前对象中__proto__中指向的构造函数名(关于__proto__。

自定义数据类型

我们在开发的时候经常需要自定义数据,比如说我们自己创建了一个构建函数F,当我们获取数据类型的时候期待返回的结果为”[object F]“,代码如下

var F = function() {}
var f1 = new F();
classString(f1);    // [object Object]

期待的结果并未返回,原因是因为Object.prototype.toString方法只定义了自带的对象类型返回,EcmaScript关于Object toString 规范:

我们可以直接重定义Object.prototype.toString:

Object.prototype.toString = function(){
    // Do something ...
}

这并不是一种很好的行为,一方面容易造成全局污染,另一方面也不利于进行排错;所以还是老老实实的在方法中判断吧:

function classString(obj, customize) {
    if (customize && obj && obj.__proto__.constructor.name) {
        return "[object " + obj.__proto__.constructor.name + "]";
    }
    return ({}).toString.call(obj);
}
var F = function() {}
var f1 = new F();
classString(f1, true);    // [object F]
classString(f1);    // [object Object]

为什么可以通过__proto__.constructor.name来获取构造函数名,object与function并不会造成混乱,object与function中的 proto 指向并不是相同的,这里不细讲,还是参考关于__proto__。

优化返回格式

对于”[object type]“数据返回我们只需要获取type即可,可以通过正则表达获取type指,这里不做代码说明。

其他

1、关于call、toString方法平常都是信手拈来使用,没有深入探究过,探究起来和以前自己脑海中的理解还是有些不同的。
2、 如果项目中需要频繁的进行数据类型的判断与获取可以考虑进行封装,简单的处理typeof与instanceof已足够。
3、上述代码中只是简单的示例,部分地方并不是十分严谨。

参考资料

EcmaScript
MDN instanceof
MDN call
MDN types Array
undefined与null有什么区别
关于__proto__与prototype
EcmaScript Object toString

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

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

相关文章

  • memcache与redis杂谈

    摘要:项目下的缓存控制客户端向服务端请求页面的过程中,服务端是可控的。可控的才可优化,优化的重点,即是缓存优化。如此就能提高数据响应的速度,也保护了数据源。虽开启扩展可管理内存,但所能管理的内存大小是有限的。见下图的英文注释注意事项 php项目下的缓存控制 客户端向服务端请求php页面的过程中,服务端是可控的。 可控的才可优化,优化的重点,即是缓存优化。 试想?数据存储在DB中,访问DB就...

    roundstones 评论0 收藏0
  • memcache与redis杂谈

    摘要:项目下的缓存控制客户端向服务端请求页面的过程中,服务端是可控的。可控的才可优化,优化的重点,即是缓存优化。如此就能提高数据响应的速度,也保护了数据源。虽开启扩展可管理内存,但所能管理的内存大小是有限的。见下图的英文注释注意事项 php项目下的缓存控制 客户端向服务端请求php页面的过程中,服务端是可控的。 可控的才可优化,优化的重点,即是缓存优化。 试想?数据存储在DB中,访问DB就...

    Mr_houzi 评论0 收藏0
  • 【译】杂谈:HTML 5的消息通知机制

    摘要:原文译文的消息通知机制译者已经被应用到开发中。所以先要征求用户的许可而不是直接显示通知。然后,获取用户许可之后,我们可以显示两种类型的信息最后执行通知代码。 原文:HTML 5 Notification 译文:HTML 5 的消息通知机制 译者:dwqs showImg(https://segmentfault.com/img/bVks7a); HTML 5 已经被应用到Web...

    darkerXi 评论0 收藏0
  • 【译】杂谈:HTML 5的消息通知机制

    摘要:原文译文的消息通知机制译者已经被应用到开发中。所以先要征求用户的许可而不是直接显示通知。然后,获取用户许可之后,我们可以显示两种类型的信息最后执行通知代码。 原文:HTML 5 Notification 译文:HTML 5 的消息通知机制 译者:dwqs showImg(https://segmentfault.com/img/bVks7a); HTML 5 已经被应用到Web...

    付伦 评论0 收藏0
  • 21_09_25 C语言杂谈

    摘要:多维数组本质上和一维数组没区别,他的维数仅仅只是作为比例因子和偏移,拿来计算地址偏移用的,但是多级指针用数组访问的时候,他的维数仅仅只做偏移用,他的过程是加偏移,解引用,加偏移,解引用。。。。 类型 c语言中规定类型这样一个事情,主要是出于一个怎样的原因呢? char sho...

    JerryZou 评论0 收藏0

发表评论

0条评论

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