在JavaScript中,如何准确获取变量的类型名是一个经常使用的问题.

但是常常不能获取到变量的精确名称,或者必须使用jQuery 中的方法,这里 我通过 typeof ,jQuery.type 和 通过构造函数来获取变量类型 这三种方法详细介绍一遍.

希望可以对你提供帮助.

看到题目的第一眼,有些同学可能会想到 typeof 运算符.


使用 typeof 获取基本的类型

在JavaScript语言中,给出了使用 typeof 运算符来获取基本的类型名.(注意不是基本类型)

这是 typeof 的全部用法

01-typeof.htm

console.log('typeof of 10 ~~~~' +typeof 10);
console.log('typeof of "a" ~~~~' +typeof 'a');
console.log('typeof of true ~~~~' +typeof true);
console.log('typeof of {} ~~~~' +typeof {});
console.log('typeof of /123/ ~~~~' +typeof /123/);
console.log('typeof of function(){} ~~~~' +typeof function(){});
console.log('typeof of undefined ~~~~' +typeof undefined);
console.log('typeof of null ~~~~' +typeof null);

这是结果

按照上面的打印结果,总结出下面要注意的几点

  • typeof (引用类型) 除了函数, 都是 'object',比如 typeof /123/

  • typeof null 为'object'

  • typeof undefined 为 'undefined',通常, 如果使用两等号, null == undefined 为真.

  • 转换为数字的常见用法 "10"-0, 如果没有转换成功,返回NaN,由于NaN 的一个特性: NaN != NaN,故判断转换成功与否的常见做法: (这也是我参见 jQuery的源码发现的,jQuery源码读100遍都不为过)

      ("10x" - 0) == ("10x" - 0);
      // 结果为假!   

使用jQuery中的方法$.type()

现在看看jQuery是怎么做的

// 先申明一个对象,目的是用来做映射
var class2type = {};
// 申明一个core_toString() 的方法,得到最原始的toString() 方法,因为在很多对象中,toStrintg() 已经被重写
var core_toString() = class2type.toString;
// 这里为 toStrintg() 后的结果和类型名做一个映射,申明一个core_toString() 后的结果,而值就是类型名
jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
    class2type[ "[object " + name + "]" ] = name.toLowerCase();
});

因为 Object.prototype.toString() 方法调用结果如下

var core_toString = {}.toString;
console.log( core_toString.call(1) );
console.log( core_toString.call("11") );
console.log( core_toString.call(/123/) );
console.log( core_toString.call({}) );
console.log( core_toString.call(function(){}) );
console.log( core_toString.call([]) );
console.log( core_toString.call(true) );
console.log( core_toString.call(new Date()) );
console.log( core_toString.call(new Error() ));
console.log( core_toString.call(null) );
console.log( core_toString.call(undefined) );
console.log( String(null) );
console.log( String(undefined) );

上面的打印结果与

class2type[ "[object " + name + "]" ] = name.toLowerCase();

不谋而合!

这是jQuery.type 的核心方法

type: function( obj ) {
    if ( obj == null ) {
        return String( obj );
    }
    // Support: Safari <= 5.1 (functionish RegExp)
    return typeof obj === "object" || typeof obj === "function" ?
        class2type[ core_toString.call(obj) ] || "object" :
        typeof obj;
},

注意,为什么把 null 或者 undefined 单独讨论呢,因为 在一些版本浏览器中

console.log(core_toString.call(null));
console.log(core_toString.call(undefined));

这是会报错的!

如果是对象类型,另:由于 在一些低版本的浏览器中,typeof /123/ 会返回的是 "function" 而不是 "object",所以这里要判断是否是函数,要明白 这里的 typeof obj === function 不是为了函数讨论的,因为函数本身就可以通过typeof 来得到类型.

 typeof obj === "object" || typeof obj === "function" ?
        class2type[ core_toString.call(obj) ]

就直接返回class2type 中键值对的结果,,如果不是,那么一定就是基本类型, 通过 typeof 就可以啦.

class2type[ core_toString.call(obj) ] || "object" :
// 这是防止一些未知情况的,如果未取到,就返回object

但是 jQuery.type 有一个很大的缺陷

这是一个自定义类型

function Person(){
   this.name = 'pawn';
}
var p = Person.toString();

// 注意,这里会打印 [object Object],通过上面的方法,无法得到精确的自定义类型
这也是 它的一个大缺陷了!

下面,我们通过构造函数的方式来获取精确类型

通过构造函数来获取类型

这种方式 是蒋坤老师( jk ) 教会我的,非常感谢他.

在理解这个方法之前,需要理解两个点

prorotype 原型属性

我们知道,任何对象或者函数都直接或者间接的继承自Object 或者 Function, (其实最终Function 是继承自 Object 的,这属于原型链的知识了)。那么,任何一个对象都具有原型对象 __proto__ (这个对象只在chrome 和 firefox 暴露,但是在其他浏览器中也是存在的),这个原型对象就是这个对象的构造函数的原型属性(这里可能有点绕).


由于 任何函数都具有 原型属性prototype,并且这个原型属性具有一个默认属性 constructor,它是这个函数的引用,看下面的代码

  function Person(){
      this.name = 'pawn';
  }
  console.log(Person.prototype.constructor === Person);


发现,这两个东西其实一个东西

但是,在某些情况下,需要这么写

  function Person(){
      this.name = 'pawn';
  }
  Person.protype = {
      XX: ... ,
      xx: ... ,
      ...
  }

这么做,就会覆盖原本的 protype 方法,那么construcor 就不存在了,这是,必须要显示的申明这个对象

  Person.protype = {
      construction: Person,
      XX: ... ,
      xx: ... ,
      ...
  }

在jQuery的中,就是这么做的,

  jQuery.fn = jQuery.prototype = {
    constructor: jQuery,
    init: function( selector, context, rootjQuery ) {
        var match, elem;

关于 jQuery对象封装的方式 也是非常值得研究


  • Function.prototype.toString()

注意,这里已经不是熟悉 [object Object],而是 已经重写了.

也就是,如果调用一个函数的toString() 方法.那么就会打印这个函数的函数体.


好了,经过上面两个步骤,你明白我要做什么了吗?

如何通过构造函数来获得变量的类型?

判断是否是基本类型

   var getType = function(obj){
       if(obj == null){
          return String(obj);
       }
       if(typeof obj === 'object' || typeof obj === 'fucntion'){
           ...
       }else{
           // 如果不是引用类型,那么就是基本类型
           return typeof obj
       }
   }

如果是对象或者函数类型

   function Person(){
       this.name = 'pawn';
   }
   var p = new Person();
   console.log(p.constructor);

现在要做的事 : 如何将Person 提取出来呢?
毋庸置疑,字符串切割那一套肯定可以办到,但是太 low 啦!
这里,我使用正则将Person提取出来

   var regex = /function\s(.+?)\(/
   function Person(){
    this.name = 'pawn';
   }
   var p = new Person();
   var c = p.constructor
   var regex = /function\s(.+?)\(/;
   console.log('|' + regex.exec(c)[1] + '|');

使用name

其实,除了上面的正则,每个函数还有一个name属性,返回函数名,但是ie8 是不支持的.

因此上面的代码可以写为:

var getType = function(obj){
    if(obj == null){
        return String(obj);
    }
    if(typeof obj === 'object' || typeof obj === 'function'){
        var constructor = obj.constructor;
        if(constructor && constructor.name){
            return constructor.name;
        }
        var regex = /function\s(.+?)\(/;
        return regex.exec(c)[1];
    }else{
        // 如果不是引用类型,那么就是基本;类型
        return typeof obj;
    }
};

但是上面的代码太丑啦,将其简化

简化

var getType = function(obj){
    if(obj == null){
        return String(obj);
    }
    if(typeof obj === 'object' || typeof obj === 'function'){
        return obj.constructor && obj.constructor.name.toLowerCase() ||
          /function\s(.+?)\(/.exec(obj.constructor)[1].toLowerCase();
    }else{
        // 如果不是引用类型,那么就是基本类型
        return typeof obj;
    }
};

还是比较麻烦,继续简化

var getType = function(obj){
    if(obj == null){
       return String(obj);
    }
    return typeof obj === 'object' || typeof obj === 'function' ?
      obj.constructor && obj.constructor.name && obj.constructor.name.toLowerCase() ||
          /function\s(.+?)\(/.exec(obj.constructor)[1].toLowerCase():
      typeof obj;
};

好了,已经全部弄完了,写个代码测试一下:

function Person(){
    this.name = 'pawn';
}
var p = new Person();

console.log(getType(p));
console.log(getType(1));
console.log(getType("a"));
console.log(getType(false));
console.log(getType(/123/));
console.log(getType({}));
console.log(getType(function(){}));
console.log(getType(new Date()));
console.log(getType(new Error()));
console.log(getType( null));
console.log(getType( undefined));

好了,关于如何获取变量的类型名就介绍到这里,希望能对你提供帮助.

JavaScript使用构造函数获取变量的类型名的更多相关文章

  1. java获取变量的类型

    对于简单类型变量,是无法直接获得变量类型的://要想获取,必须自定义函数进行返回 对于包装类型变量,是可以直接获得的,变量名称.getClass().getName(); java中获取变量的类型可以 ...

  2. JavaScript基础系列(变量与类型)

    以下内容将JavaScript简称为JS 打开本文时不管你是零基础的初学者还是其他语言的老兵,我都想说程序语言的基础支撑起了整个网络世界,不把这些基础学透之后稍复杂的内容会让你寸步难行. 现在先给编程 ...

  3. javascript中检测一个变量的类型

    /** * 怎么检测一个变量的类型? * 在js中检测对象类型主要有三种:typeof, instanceof, constructor, 这几种都可以检测对象的类型. * 另外还可以适应jQuery ...

  4. Python3基础 type获取变量的类型

    镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...

  5. 使用typeid(变量或类型).name()来获取常量或变量的类型---gyy整理

    使用typeid(变量或类型).name()来获取常量或变量的类型 <typeinfo>  该头文件包含运行时类型识别(在执行时确定数据类型)的类 typeid的使用   typeid操作 ...

  6. typeof获取变量的数据类型 javascript

    获取变量的数据类型:typeof <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  7. C# 中反射获取某类的子类和根据类型名动态创建对象

    有时候,为了快速批量处理已经实现某个基类或者某个接口的子类,需要通过反射的方式获取到他们的类类型(Type),然后再通过 1 Activator.CreateInstance(objType); 或者 ...

  8. php设置和获取变量类型

    1. 获取变量类型 gettype($a); 2. 设置变量类型 settype($a,'int'); 3. 测试函数 is_array();是否数组 is_string();是否字符串 is_obj ...

  9. 【javascript】详解变量,值,类型和宿主对象

    前言 我眼中的<javascript高级程序设计> 和<你不知道的javascript>是这样的:如果<javascript高级程序设计>是本教科书的话, < ...

随机推荐

  1. vim颜色选择+按&lt;F9&gt;自动编译运行+其他基本配置(ubuntu)

    (以下是ubuntu上的配置........ 但如果你是在window上的,直接用一下配置吧(懒得介绍了)=.= syntax on filetype indent plugin on set rul ...

  2. BZOJ1035 : [ZJOI2008]Risk

    首先要将这个图连通,方法是通过扫描线+set求出每个连通块最高的点上方的第一条边,然后向交点连边. 然后把边拆成两条双向边,每次找到一条没走过的边,找到极角排序后它的反向边的后继,直到回到这条边.根据 ...

  3. Leetcode#115 Distinct Subsequences

    原题地址 转化为求非重路径数问题,用动态规划求解,这种方法还挺常见的 举个例子,S="aabb",T="ab".构造如下地图("."表示空位 ...

  4. Find mac address

    Windows Method 1: Using the Command Prompt 1 Click on the Start button.   2 Type cmd in the search b ...

  5. Python 操作Redis

    redis对比monoDB: redis和memcache 是key value非关系型数据库,mysql是关系型数据库,表的结构和保存的内容有严格的要求,关系型数据库无法保存临时数据或不标准的数据, ...

  6. nginx常用配置系列-HTTPS配置

    接上篇,nginx配置系列 HTTPS现在已经很流行,特别是AppStore上线的应用要求使用HTTPS进行通信,出于安全考虑也应该使用HTTPS,HTTPS配置需要准备证书文件,现在也有很多免费证书 ...

  7. SNS团队Beta阶段第五次站立会议(2017.5.26)

    1.立会照片 2.每个人的工作 成员 今天已完成的工作 明天计划完成的工作 罗于婕 生词本功能测试,bug修复 发音图标的改进 龚晓婷 辅助完善历史纪录的功能 对于历史记录功能的测试 林仕庄 继续完善 ...

  8. vertica系列:数据的导入导出

    本文仅涉及 Vertica 导入导出本地文件, 以及两个 Vertica 集群相互导出, 不涉及 Vertica 和 hdfs/Hive 导入导出和互操作. copy 数据导入工具 copy 命令无疑 ...

  9. button 去掉原生边框

    button按钮触发 hover 时,自带边框会显示,尤其是 button 设置圆角时,如图: 解决办法: outline: 0;

  10. PAT 1083 是否存在相等的差

    https://pintia.cn/problem-sets/994805260223102976/problems/994805260780945408 给定 N 张卡片,正面分别写上 1.2.…… ...