的繼承在很多書里面細(xì)致的分了很多種類型和實(shí)現(xiàn)方式,大體上就是兩種對(duì)象冒充、原型方式。這兩種方式各有優(yōu)點(diǎn)和缺陷,這里我給你先列舉出來,再從底層分析區(qū)別。我們看到了,在Js版本更新的過程中,為了更方便的執(zhí)行這種上下文this的切換以達(dá)到繼承或者更加廣義的目的,增加了call和apply函數(shù)。所以說盡管call和apply并不是僅僅為了繼承而新增的方法,但用它們可以模擬繼承。
javascript繼承有哪兩種形式
在很多書里,繼承分為很多類型和實(shí)現(xiàn)方法,一般是兩種:對(duì)象模擬和原型方法。這兩種方法各有利弊。這里我先給大家列舉一下,然后從底層分析一下區(qū)別:(1)對(duì)象冒充A(name){ this . name = name;這個(gè)。=(){alert(this.name+"sayHello!");};}B(name,id){ this . temp = A;this.temp(名稱);//相當(dāng)于newA();this.temp//防止超類A的屬性和方法將來被temp引用覆蓋this.id = id這個(gè)。=(ID){ alert(this . ID = = ID)};}構(gòu)造對(duì)象B時(shí),調(diào)用temp相當(dāng)于啟動(dòng)A的構(gòu)造函數(shù),注意這里上下文中的這個(gè)對(duì)象是B的實(shí)例,所以在執(zhí)行A的構(gòu)造函數(shù)腳本時(shí),A的所有變量和方法都會(huì)賦給這個(gè)所指向的對(duì)象,也就是B的實(shí)例,從而達(dá)到B繼承A的屬性方法的目的,刪除臨時(shí)引用temp后, 是為了防止維護(hù)B中A的類對(duì)象(注意不是實(shí)例對(duì)象)的引用改變,因?yàn)楦淖僼emp會(huì)直接導(dǎo)致A類的結(jié)構(gòu)改變(注意不是A類的對(duì)象)。 我們可以看到,在Js版本更新的過程中,加入了call和apply函數(shù),是為了更方便的切換這個(gè)上下文,達(dá)到繼承或者更通用的目的。它們的原理是一樣的,只是參數(shù)的版本不同(一個(gè)變量是任意參數(shù),而一個(gè)參數(shù)集必須傳入數(shù)組)。這里以call為例說明call實(shí)現(xiàn)的對(duì)象假裝被繼承。Rect(width,){ this.width = width這個(gè)。=;this.area=(){this.width*this。;};}(width,,name){Rect.call(this,width,);this.name = namethis . show =(){ alert(this . name+" with area:"+this . area());}}關(guān)于調(diào)用方法,官方解釋:調(diào)用一個(gè)對(duì)象的方法,用另一個(gè)對(duì)象替換當(dāng)前對(duì)象。Call(,arg1,arg2…)這也是對(duì)象模擬的繼承。實(shí)際上,調(diào)用call方法時(shí)發(fā)生的也是上下文環(huán)境變量this的替換。在函數(shù)體中,這必須指向類對(duì)象的實(shí)例。但是,使用它作為上下文環(huán)境變量會(huì)調(diào)用Rect方法,即Rect類的構(gòu)造函數(shù)。所以當(dāng)Rect被調(diào)用時(shí),它的賦值屬性和方法實(shí)際上是在一個(gè)新的對(duì)象上執(zhí)行的。所以雖然call和apply并不是僅僅針對(duì)繼承的新方法,但是它們可以模擬繼承。對(duì)象模仿繼承就是這樣的東西,它可以實(shí)現(xiàn)多重繼承,只需要重復(fù)賦值的過程。然而目前并沒有大規(guī)模使用。為什么?因?yàn)樗幸粋€(gè)明顯的性能缺陷,所以有必要說一下OO的概念。我們說對(duì)象是成員+成員方法的集合。構(gòu)造對(duì)象實(shí)例時(shí),這些實(shí)例只需要有自己的成員變量。成員方法只是一個(gè)對(duì)變量進(jìn)行操作的可執(zhí)行文本區(qū)域。不需要為每個(gè)實(shí)例復(fù)制這個(gè)區(qū)域,所有實(shí)例都可以共享。現(xiàn)在回到Js對(duì)模擬對(duì)象的繼承,所有的成員方法都是為此而創(chuàng)建的,也就是所有的實(shí)例都會(huì)有一個(gè)成員方法的副本,這是對(duì)內(nèi)存資源的極度浪費(fèi)。其他的缺陷,比如對(duì)象冒充變量,方法不能繼承域,就不用提了。我覺得前一個(gè)致命缺陷就夠了。但是我們還是要了解一下,尤其是父類的屬性和方法是如何繼承的原理,這對(duì)理解Js繼承非常重要。㈡原型。第二種類型的繼承是原型。所謂原型繼承,就是以某種方式使用或覆蓋,從而達(dá)到復(fù)制屬性方法的目的。實(shí)現(xiàn)的方式有很多種,不同的框架可能會(huì)有一些差異,但是如果把握住了原理,就沒有什么不懂的了??匆粋€(gè)例子(某種實(shí)現(xiàn)):(){ { this.name = " Mike這個(gè)。=(){alert("!");};}..=(){alert("你好!");};(){}.= new();關(guān)鍵是把prototype屬性賦給最后一句中類構(gòu)造的對(duì)象。在這里,作者解釋了如何將父類的屬性和方法復(fù)制到子類中。Js讀取一個(gè)對(duì)象的屬性時(shí),總是先看自己域的屬性列表,如果有就返回;否則,它將讀取域(每個(gè)對(duì)象共享構(gòu)造該對(duì)象的類的域的所有屬性和方法),如果找到,它將返回。因?yàn)樗梢灾赶蚱渌麑?duì)象,Js解釋器將遞歸地尋找域所指向的域