zoukankan      html  css  js  c++  java
  • JavaScript使用构造函数获取变量的类型名

    这个题很有意思?

    x

    想想为啥??

    有时会看到:

    Object.prototype.toString.call()

    toString()是一个怎样的方法,他定义在哪里呢?

    很多人就会在想,为神马

    获取对象类型,为什么用 Object.prototype.toString.call(obj) 而不用 obj.toString() 呢?

    参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/toString

     其实说白了,就是怕你重写了toString,所以才要用object 最原始的他toString,所以才去call:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
            <script type="text/javascript">
                function A(){
                    this.say=function(){
                        console.log("我是1");
                    }
                }
                function B(){
                    this.say=function(){
                        console.log("我是2");
                    }
                }
                var a=new A();
                var b=new B();
                a.say.call(b);    //我是1
            </script>
        </head>
        <body>
        </body>
    </html>
    

      

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
            <script type="text/javascript">
                function A(){
                    this.name='SB';
                    this.say=function(){
                        console.log("我是1");
                    }
                }
                function B(){
                    A.call(this);   //B继承A,重写say方法
                    this.say=function(){
                        console.log("我是2");
                    }
                }
                var a=new A();
                var b=new B();
                console.log(b.name);  //SB
                b.say();         //我是2
                a.say.call(b);    //我是1
            </script>
        </head>
        <body>
        </body>
    </html>
    

      

     至于为啥???看http://www.cnblogs.com/libin-1/p/5902070.html

     

    它是能将某一个值转化为字符串的方法。然而它是如何将一个值从一种类型转化为字符串类型的呢?

    通过下面几个例子,我们便能获得答案:

    1.将boolean类型的值转化为string类型:

    console.log(true.toString());//"true"console.log(false.toString());//"false"

    2.将string类型按其字面量形式输出:

    var str = "test123y";console.log(str.toString());//"test123y"

    3.将Object类型转化成string类型(JavaScript原生的Array类型、Date类型、RegExp类型以及Number、Boolean、String这些包装类型都是Object的子类型):

    自定义Object类型(没有重新定义toString方法):
    var obj = {name:"Tom", age:18};console.log(obj.toString());//"[object Object]"此时调用的是从Object继承来的原始的toString()方法

    接下来的三个例子都是以重写的方式实现了toString()方法;

    1.Array类型:

    var arr = ["tom",12,"rose",18];console.log(arr.toString());//"tom,12,rose,18"

    2.RegExp类型

    var patten = new RegExp("//[hbc//]at", "gi");console.log(patten.toString());//"//[hbc/]at/gi"

    3.Date类型

    var date = new Date(2014,02,26);//注意这种格式创建的日期,其月份是3月console.log(date.toString());//"Wed Mar 26 2014 00:00:00 GMT+0800"输出格式因浏览器不同而不同,此为firefox的输出格式;

    4.Number类型也是以重写的方式实现toString()方法的,请看以下例子:

    (1)它可以接受一个整数参数,并将调用这个方法的数值转化成相应进制的字符串:

    var num = 16;console.log(num.toString(2));//10000 二进制console.log(num.toString(8));//20 八进制console.log(num.toString(16));//10 十六进制console.log(num.toString(5));//31 虽然没有五进制,但是这样传参是可以被toString()方法接受的

    (2)再看下面的代码:

    console.log(1.toString());//这种写法会报错语法错误,但是下面的写法都是合法的;console.log((1).toString());//"1"console.log(typeof (1).toString());//stringconsole.log(1..toString());//"1"console.log(typeof (1).toString());//stringconsole.log(1.2.toString());//"1"console.log(typeof (1).toString());//string

    这是因为javascript引擎在解释代码时对于“1.toString()”认为“.”是浮点符号,但因小数点后面的字符是非法的,所以报语法错误;而后面的“1..toString()和1.2.toStirng()”写法,javascript引擎认为第一个“.”小数点,的二个为属性访问语法,所以都能正确解释执行;对于“(1).toStirng()”的写法,用“()”排除了“.”被视为小数点的语法解释,所以这种写法能够被解释执行;

    (3)纯小数的小数点后面有连续6或6个以上的“0”时,小数将用e表示法进行输出;

    var num = 0.000006;//小数点后面有5个“0”console.log(num.toString());//"0.000006"var num = 0.0000006;//小数点后面有6个“0”console.log(num.toString());//"6e-7"

    (4)浮点数整数部分的位数大于21时,输出时采用e表示法;

    var num = 1234567890123456789012;console.log(num.toString());//"1.2345678901234568e+21"

    看到这里大家难免会有些疑问,这些基本的数据类型的值都是常量,而常量是没有方法的,为什么能够调用方法呢?答案是这样的,五种基本类型除了null、undefined以外都有与之对应的特殊的引用类型——包装类型。当代码被解释执行时,底层会对基本类型做一个类型转换,即将基本类型转换成引用类型,这样就可以调用相应引用类型有权访问到的方法。

    二、toString()方法定义在何处?

    运行以下代码:

    var pro = Object.prototype;var pr = pro.__proto__;//ie11之前版本不支持该属性console.log(typeof pro);//"object"console.log(String(pro));//"[object Object]"console.log(pro.hasOwnProperty("toString"));//trueconsole.log(typeof pr);//"object"console.log(String(pr));//"null"console.log(pr.hasOwnProperty("toString"));//报错

    由此可知,toString()定义在Object.prototype上;

    三、使用Object.prototype上的原生toString()方法判断数据类型,使用方法如下:

    Object.prototype.toString.call(value)

    1.判断基本类型:

    Object.prototype.toString.call(null);//”[object Null]”Object.prototype.toString.call(undefined);//”[object Undefined]”Object.prototype.toString.call(“abc”);//”[object String]”Object.prototype.toString.call(123);//”[object Number]”Object.prototype.toString.call(true);//”[object Boolean]”

    2.判断原生引用类型:

    函数类型

    Function fn(){console.log(“test”);}Object.prototype.toString.call(fn);//”[object Function]”

    日期类型

    var date = new Date();Object.prototype.toString.call(date);//”[object Date]”

    数组类型

    var arr = [1,2,3];Object.prototype.toString.call(arr);//”[object Array]”

    正则表达式

    var reg = /[hbc]at/gi;Object.prototype.toString.call(arr);//”[object Array]”

    自定义类型

    person = new Person("Rose", 18);Object.prototype.toString.call(arr); //”[object Object]”

    很明显这种方法不能准确判断person是Person类的实例,而只能用instanceof 操作符来进行判断,如下所示:

    console.log(person instanceof Person);//输出结果为true

    3.判断原生JSON对象:

    var isNativeJSON = window.JSON && Object.prototype.toString.call(JSON);console.log(isNativeJSON);//输出结果为”[object JSON]”说明JSON是原生的,否则不是;
    注意:Object.prototype.toString()本身是允许被修改的,而我们目前所讨论的关于Object.prototype.toString()这个方法的应用都是假设toString()方法未被修改为前提的。

    在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或+"10", 如果没有转换成功,返回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));

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

  • 相关阅读:
    C# 还原SQL数据库(非存储过程方式)
    C# 无边框窗体移动代码
    SQL 2008 R2 数据库镜像操作
    序列号
    Oracle VM VirtualBox 随系统自动启动虚拟机的方法
    SQL每个用户最后的一条记录
    JS判断是否在微信浏览器打开
    使用device.js检测设备并实现不同设备展示不同网页
    check单选框多个全选与取消全选
    判断滚动是否到达底部
  • 原文地址:https://www.cnblogs.com/libin-1/p/5901580.html
Copyright © 2011-2022 走看看