摘要:并且,在創建子類型的實例時,無法向超類型的構造函數傳遞參數。借用構造函數經典繼承在子類型構造函數的內部調用超類型構造函數。缺點是同樣具有構造函數模式創建對象的固有弊端構造函數中煩人方法函數對象重復創建。
創建對象的幾種方式
在邏輯上從低級到高級:工廠模式、構造函數模式、原型模式、組合模式。當然還有其他模式,但是這四者邏輯關系強,總結起來很有感覺。之所以和繼承一起分析,也是因為邏輯關系很清晰:原型模式對應原型鏈繼承,構造函數模式對應借用構造函數模式繼承,組合模式對應組合繼承。邏輯上按照“哪個模式有什么缺點,為什么有這個缺點,我們怎么解決這個缺點”逐步分析,這樣分析完后就會豁然開朗。
1)工廠模式使用函數創建對象,該函數來封裝創建對象的細節。
function createObject(para1,para2,para3){ var o = new Object();//顯式創建對象 o.colors = [para1, para2, para3]; o.sayColors = function() { console.log(this.colors[0]); } return o;//返回對象 } var ob1 = createObject("red", "green", "blue"); console.log(ob1); console.log(ob1.colors); ob1.sayColors(); console.log(ob1 instanceof createObject);//false,無法判斷對象的類型 缺點:無法判斷對象類型。2)構造函數模式
通過構造函數創建的實例被標識為一種特定的類型,可以通過instanceof 判斷對象類型。
function createObject(para1, para2, para3) { //通過this完成函數屬性定義,不用顯示創建對象,因此也不用返回對象 this.colors = [ para1, para2, para3 ]; this.sayColors = function () { console.log(this.colors[0]); } } var ob1 = new createObject("red", "green", "blue"); console.log(ob1); console.log(ob1.colors); ob1.sayColors(); console.log(ob1 instanceof createObject); //true,可以判斷對象的類型
缺點:通過構造函數創建的實例具有不同的方法和屬性,屬性可以不同,這對實例來說是好的,我們希望實例屬性獨立。但是方法即函數,函數即對象,也就是說創建了太多重復的對象。
var ob1 = new createObject("red", "green", "blue"); var ob2 = new createObject("red", "green", "blue"); alert(ob1.sayColors == ob2.sayColors);//false,不同實例具有不同的方法
解決方式:把方法的定義放到構造函數外部,即在構造函數內部引用外部全局函數。這樣就可以一次定義,多次引用。但是當外部全局函數增多時,明顯降低了封裝性,《JavaScript精粹》上提到,全局對象是EScript的一大敗筆。
值得一提的是,構造函數創建的實例中的引用類型屬性是很特殊的,這一點會隨后提到。
3) 原型模式:每一個函數都有一個prototype屬性,這個屬性指向通過構造函數創建的實例對象的原型對象。原型對象的方法和屬性可以被它的所有實例共享。因此,通過把屬性和方法添加到實例的原型對象上,可以實現屬性和方法共享。
缺點:“成也蕭何,敗也蕭何”,原型模式的缺點就在于過強的共享能力,方法的共享可以減少多余的對象實例創建。但是屬性共享導致實例難以擁有自己獨特屬性。當然,如果是一些不會修改的屬性值,共享也就罷了;但是如果是需要修改的屬性,并且該屬性值是引用類型(基本類型屬性值可以在實例中定義,會覆蓋掉原型屬性,但是不會修改原型屬性,其他的實例訪問該屬性依舊對應原型屬性),那么實例對這個屬性值的修改就會在原型中反映出來,這其實就是修改了原型。糟糕的是其他實例中的該屬性也同步變化,然后就會出現奇怪的問題。
4) 組合模式(最常用的一種對象創建方式,兼顧優點,避免缺點)
:使用構造函數模式定義各個實例屬性,使用原型模式定義方法和共享的屬性。
補充關于對象的幾個方法:
isPrototypeOf(): 確定一個對象是否是另一個對象的原型,只要是原型鏈中出現的原型,就返回true,使用方法:
alert(createObject.prototype.isPrototypeOf(ob1));//rue
instanceof操作符:檢測是否是某一構造函數的實例,前面的參數是實例, 后面的的參數是構造函數名,只要是原型鏈中出現的構造函數就返回true。
alert(ob1 instanceof createObject);//true
hasOwnProperty(): 檢測一個實例是否擁有某個屬性,使用方法
alert(ob1.hasOwnProperty("colors"));//true
in操作符:多帶帶使用時可以檢查實例屬性或者原型屬性是否存在,in后跟的一般是實例,因此可以理解為檢查實例以及實例對應的原型中是否有這個屬性或非法。使用方法:
alert("sayColors" in ob1);//true alert("sayColors" in createObject);//false,直接對原型檢查沒意義
for in 的另一種用法,類似于數組的forEach()方法,是一個循環,返回實例或原型中的可枚舉的屬性。
繼承的實現: 1.原型鏈
:把超類型的實例復制給子類型的原型,這樣超類型的方法和屬性就由子類型繼承。
問題:子類型原型會繼承超類型實例的屬性,如果這個屬性值是引用類型,就會導致子類型的所有實例都共享了這個屬性,導致不同實例屬性的耦合,這是原型模式創建對象的固有問題。并且,在創建子類型的實例時,無法向超類型的構造函數傳遞參數。因此,實際中很少多帶帶使用原型鏈。
2 借用構造函數(經典繼承)在子類型構造函數的內部調用超類型構造函數。這個方法之所以被稱為借用構造函數,我覺得就是因為這種方法和前面介紹的通過構造函數創建實例的私有屬性是一樣的道理,只不過是在子類型構造函數內部調用了超類型構造函數。
而且可以在創建子類型實例時向超類型傳遞參數,因為這就相當于調用了一個函數,函數當然是可以有參數的。
缺點是同樣具有構造函數模式創建對象的固有弊端:構造函數中煩人方法(函數對象)重復創建。并且,只有在超類型構造函數中定義的屬性和方法才會被繼承,通過超類型原型定義的方法和屬性對子類型不可見,這是因為只執行了構造函數內部的語句。因此實際中這個方法也很少多帶帶使用。
3 組合繼承(偽經典模式繼承)
將原型鏈繼承和借用構造函數模式組合到一起,使用原型鏈實現對原型屬性和方法的繼承(實現了方法復用),但是通過借用構造函數實現對實例屬性的繼承(實現了實例屬性私有)。避免了缺陷,融合了優點,是最常用的繼承模式,而且,instanceof操作符和isPrototypeOf()都適用于組合繼承創建的對象。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80555.html
摘要:介一回,偶們來聊一下用中的類,有些盆友可能用過或者的,知道語法糖,可是在中并沒有,中需要用到構造函數來模擬類。而且要注意一點,構造函數沒有語句,是自動返回。 本回內容介紹 上一回聊到JS的Function類型,做了柯里化,數組去重,排序的題。 介一回,偶們來聊一下用JS中的類,有些盆友可能用過ES6或者TypeScript的,知道Class語法糖,可是在ES5中并沒有,ES5中需要用到...
摘要:在最開始的時候,原型對象的設計主要是為了獲取對象的構造函數。同理數組通過調用函數通過調用原型鏈中描述了原型鏈的概念,并將原型鏈作為實現繼承的主要方法。 對象的創建 在JavaScript中創建一個對象有三種方式。可以通過對象直接量、關鍵字new和Object.create()函數來創建對象。 1. 對象直接量 創建對象最直接的方式就是在JavaScript代碼中使用對象直接量。在ES5...
摘要:高程讀書筆記第六章理解對象創建自定義對象的方式有創建一個實例,然后為它添加屬性和方法。創建了自定義的構造函數之后,其原型對象默認只會取得屬性至于其他方法都是從繼承而來的。 JS高程讀書筆記--第六章 理解對象 創建自定義對象的方式有創建一個Object實例,然后為它添加屬性和方法。還可用創建對象字面量的方式 屬性類型 ECMAScript在定義只有內部采用的特性時,描述了屬性的各種特征...
showImg(http://img3.douban.com/lpic/s8958650.jpg); 0x00 javascript組成 ECMAScript(-265)核心語言部分 DOM文檔對象模型(DOM1、2、3) BOM瀏覽器對象模型(提供與瀏覽器交互的接口和方法) 0x01 async 異步加載 執行順序不定 charset defer 延遲加載,立即下載腳本但不執行 src ...
閱讀 1090·2021-11-15 18:00
閱讀 2802·2021-09-22 15:18
閱讀 1964·2021-09-04 16:45
閱讀 750·2019-08-30 15:55
閱讀 3853·2019-08-30 13:10
閱讀 1331·2019-08-30 11:06
閱讀 1983·2019-08-29 12:51
閱讀 2294·2019-08-26 13:55