javascript
《JS权威指南学习总结--9.5 类和类型》
內容要點:
??? 介紹了三種用以檢測任意對象的類的技術,instanceof運算符、constructor屬性,以及構造函數的名字。
??? 但每種技術都不甚完美,本節總結了鴨式辯型,這種編程哲學更加關注對象可以完成什么工作(它包含什么方法)而不是對象屬于哪個類
?一.instanceof運算符
???? 1.左操作數是帶檢測其類的對象,右操作數是定義類的構造函數。如果o繼承自c.prototype,則表達式 o instanceof c值為true.這里的繼承可以不是直接繼承,如果o所繼承的對象繼承自另一個對象,后一個對象繼承自c.prototype,這個表達式的運算結果也是true,
???? 2.構造函數是類的公共標識,但原型是唯一的標識。盡管Instanceof運算符的右操作數是構造函數,但計算過程實際上是檢測了對象的繼承關系,而不是檢測創建對象的構造函數。
???? 3.isPrototypeOf()方法:不使用構造函數作為中介,來檢查對象的原型鏈上是否存在某個特定的原型對象。
??????? range.methods.isPrototypeOf(r); //range.method 是原型對象
???? 4.instancof運算符和isProtootypeOf()方法的缺點是:
???????? 我們無法通過對象來獲得類名,只能檢測對象是否屬于指定的類名。
???????? 在客戶端JS中還有一個比較嚴重的不足,就是在多窗口和多框架子頁面的Web應用中兼容性不佳。每個窗口和框架子頁面都具有單獨的執行上下文,每個上下文都包含獨有的全局變量和一組構造函數。在兩個不同框架頁面中創建的兩個數組繼承自兩個相同但相互獨立的原型對象,其中一個框架頁面中的數組不是另一個框架頁面的Array()構造函數的實例,instanceof運算結果是false。
二.constructor屬性
???? 1.另一種識別對象是否屬于某個類的方法是使用constructor屬性,因為構造函數是類的公共標識,所以最直接的方法就是使用constructor屬性,比如:
???????? function typeAndValue(x){
??????????? if(x == null ) return ""; //Null和undefined沒有構造函數
??????????? switch(x.constructor){
????????????? case Number : return "Number" + x; //處理原始類型
????????????? case String : return "String: ' " + x + " ' ";
????????????? case Date : return "Date" + x; //處理內置類型
????????????? case RegExp : return "RegExp:" + x;
????????????? case Complex : return "Complex:" + x; //處理自定義類型
??????????????? }
?????????? }
???? 需要注意的是,在代碼中關鍵字case后的表達式都是函數,如果改用typeof運算符或獲取到對象的class屬性的話,它們應當改為字符串。
???? 2.使用constructor屬性檢測對象屬于某個類的技術的不足之處和instanceof一樣。在多個執行上下文的場景中它是無法正常工作的(比如在瀏覽器窗口的多個框架子頁面中)。在這種情況下,每個框架頁面各自擁有獨立的構造函數集合,一個框架頁面中的Array構造函數和另一個框架頁面的Array構造函數不是同一個構造函數。
??????? 同樣,在javascript中也并非所有的對象都包含constructor屬性。在每個新創建的函數原型上默認會有constructor屬性,但我們常常會忽覺原型上constructor屬性。比如例9-1和例9-2它們的實例都沒有constructor屬性。
三.構造函數的名稱
? ? 1.使用instanceof運算符和constructor屬性來檢測對象所屬的類有一個主要的問題,在多個執行上下文中存在構造函數的多個副本的時候,這兩種方法的檢測結果會出錯。多個執行上下文中的函數看起來是一模一樣,但它們是相互獨立的對象,因此彼此也不相等。
? ? 2.一種可能的解決方案是使用構造函數的名字而不是使用構造函數本身作為類標識符。
?????? 一個窗口里的Array構造函數和另一個窗口的Array構造函數是不相等的,但是它們的名字是一樣的。
?????? 在一些js的實現中為函數對象提供了一個非標準的屬性name,用來表示函數的名稱。
?????? 對于那些沒有name屬性的javascript實現來說,可以將函數轉換為字符串,然后從中提取出函數名。?
??? 3.例9-4:可以判斷值的類型的typeof()函數?
?????? /*以字符串形式返回o的類型:如果o是null,返回"null";如果o是NaN,返回"nan"。。。如果typeof所返回的值不是"object",則返回這個值。。如果o的類不是"object",則返回這個值,,如果o包含構造函數并且這個構造函數具有名稱,則返回這個名稱,,,否則,一律返回"object"。*/
??????? function type (o){
?????????? var t,c,n;? //type,class,name
?????????? //處理null值的特殊情況
?????????? if(o===null)return "null";
?????????? //另外一種特殊情況:NaN和它自身不相等
????????? if(o!==o) return "nan";
?????????? //如果typeof的值不是"object",則使用這個值,這可以識別出原始值得類型和函數
?????????? if((t == typeof o)!=="object") return t;
????????? //返回對象的類名,除非值為"object",這種方式可以識別出大多數的內置對象。
????????? if((c == classof(o))!=="Object") return c;
???????? //如果對象構造函數的名字存在的話,則返回它
????????? if(o.constructor && typeof o.constructor === "function" && (n = o.constructor.getName())) return n;
????????? //其他的類型都無法判別,一律返回"Object"
????????? return "Object";
???????? }
??????? //返回對象的類
??????? function classof(o){
????????? return Object.prototype.toString.call(o).slice(8,-1);
???????? };
??????? //返回函數的名字(可能是空字符串),不是函數的話返回null
???????? Function.prototype.getName = function(){
??????????? if("name" in this) return this.name;
??????????? return this.name = this.toString().match(/function\s*([^(]*)\(/)[1])
????????? };
???????? var a = new Date();//Date
?? ??? ? var b = [1,2,3]; //Array
?? ??? ? var c = {}; //Object
?? ??? ? var d = true; //boolean
?? ??? ? var e = "1"; //string
?? ??? ? var f = 1;//number
?? ??? ? var g = function(){};//function
?? ??? ? var h = new Function(); //function
???????? console.log(type(g));
???????? 這種使用構造函數名字來識別對象的類的做法和使用constructor屬性一樣有一個問題:并不是所有的對象都具有constructor屬性。此外,并不是所有的函數都有名字。如果使用不帶名字的函數定義表達式定義一個構造函數,getName()方法則會返回空字符串:
???????? //這個構造函數沒有名字
???????? var Complex = function(x,y){ this.r = x;this.i=y; }
???????? //這個構造函數有名字
???????? var Range = function Range(f,t){ this.from = f;this.to = t; }
轉載于:https://www.cnblogs.com/hanxuming/p/5849476.html
總結
以上是生活随笔為你收集整理的《JS权威指南学习总结--9.5 类和类型》的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu 16.04 桌面菜单栏 任
- 下一篇: 08-SSH综合案例:前台用户模块:注册