• JavaScript使用构造函数获取变量的类型名


    在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 = /functions(.+?)(/
       function Person(){
        this.name = 'pawn';
       }
       var p = new Person();
       var c = p.constructor
       var regex = /functions(.+?)(/;
       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 = /functions(.+?)(/;
            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() || 
              /functions(.+?)(/.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() ||
              /functions(.+?)(/.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));

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

  • 相关阅读:
    Cannot find or open the PDB file from http://bbs.csdn.net/topics/350149584 呼吁大家忽视结贴率为0的求助。
    使用GDI+位图数据扫描线处理图像的小技巧 from http://blog.csdn.net/maozefa/article/details/4533770
    解决Visual C++ 编译器中混合 .c 文件时收到 C1853 预编译头错误的方法 from http://live.aulddays.com/tech/08/c1853precompile/
    使用GDI+保存用户的绘图数据.
    char、varchar、text和nchar、nvarchar、ntext的区别
    ASP.NET Cache
    ECMAScript 引用类型
    Meta标签——网站中必不可少的一部分
    ECMAScript 原始类型
    web性能测试分析工具篇
  • 原文地址:https://www.cnblogs.com/libin-1/p/5840667.html
Copyright © 2020-2023  润新知