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 = /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));

好了,關於如何獲取變量的類型名就介紹到這里,希望能對你提供幫助.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM