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