摘要:構(gòu)造函數(shù)繼承在子類的構(gòu)造函數(shù)中,通過或的形式,調(diào)用父類構(gòu)造函數(shù),以實(shí)現(xiàn)繼承。所以,其實(shí)多帶帶使用原型鏈繼承或者借用構(gòu)造函數(shù)繼承都有自己很大的缺點(diǎn),最好的辦法是,將兩者結(jié)合一起使用,發(fā)揮各自的優(yōu)勢。使指向自己而不是指向構(gòu)造函數(shù)
原型鏈繼承
子類的所有實(shí)例都共享著原型上的所有屬性和方法。通過子類實(shí)例,可以訪問原型上的屬性,但是,不能重寫原型上的屬性。
//定義一個(gè)學(xué)生類 function Student(stuID, schoolName) { this.stuID = stuID; this.schoolName = schoolName; } //所有學(xué)生都有這樣一個(gè)特征 Student.prototype.characteristic = "年輕有朝氣"; var stu1 = new Student(1001,"第一小學(xué)"); console.log(stu1.stuID); //1001 console.log(stu1.characteristic); //"年輕有朝氣" //重寫characteristic stu1.characteristic = "活潑可愛"; console.log(stu1.characteristic); //"活潑可愛" var stu2 = new Student(1002,"第一小學(xué)"); console.log(stu2.characteristic); //"年輕有朝氣" console.log(Student.prototype); //{characteristic: "年輕有朝氣"}
上面這段代碼表明:
通過stu1.characteristic = "活潑可愛";并沒有改變原型上的屬性值。
當(dāng)實(shí)例中,存在和原型中同名的屬性時(shí),會(huì)自動(dòng)屏蔽原型上的同名屬性。stu1.characteristic = = "活潑可愛" 實(shí)際上是給實(shí)例stu1添加了一個(gè)本地屬性 characteristic,所以當(dāng)我們再次訪問stu1.characteristic 時(shí),訪問的是實(shí)例的本地屬性,而不是原型上的characteristic屬性(它因和本地屬性名同名已經(jīng)被屏蔽了)。
原型上的 characteristic 值是一個(gè)基本類型的值,如果是一個(gè)引用類型呢?這其中又會(huì)有一堆小九九。
其實(shí)原型上任何類型的值,都不會(huì)被實(shí)例所重寫。在實(shí)例上設(shè)置與原型上同名屬性的值,只會(huì)在實(shí)例上創(chuàng)建一個(gè)同名的本地屬性。但是,原型上引用類型的值可以通過實(shí)例進(jìn)行修改,而且所有的實(shí)例訪問到的該引用類型的值也會(huì)隨之改變。(不是很明白,既然引用類型的值都能被修改了,那么為什么還說不會(huì)被實(shí)例重寫??難道修改!= 重寫)
//定義一個(gè)學(xué)生類 function Student(stuID, schoolName) { this.stuID = stuID; this.schoolName = schoolName; } //所有學(xué)生都有這樣一個(gè)特征 Student.prototype.characteristic = "年輕有朝氣"; Student.prototype.examItems = ["語文","數(shù)學(xué)","英語"]; //考試項(xiàng)目 var stu1 = new Student(1001, "第一小學(xué)"); console.log(stu1.examItems); //["語文","數(shù)學(xué)","英語"] //修改examItems stu1.examItems.push("科學(xué)"); console.log(stu1.examItems); //["語文","數(shù)學(xué)","英語","科學(xué)"] var stu2 = new Student(1002, "第一小學(xué)"); console.log(stu2.examItems); //["語文","數(shù)學(xué)","英語","科學(xué)"]
原型上任何類型的屬性值都不會(huì)通過實(shí)例被重寫,但是引用類型的屬性值會(huì)受到實(shí)例的影響而修改。
構(gòu)造函數(shù)繼承在子類的構(gòu)造函數(shù)中,通過 apply( ) 或 call( )的形式,調(diào)用父類構(gòu)造函數(shù),以實(shí)現(xiàn)繼承。
//定義一個(gè)超類/父類: 人 function Person (name, age) { //人都有姓名,年齡,會(huì)吃飯,會(huì)睡覺 //傳入出生年份 year,自動(dòng)計(jì)算年齡 this.name = name; this.age = age; this.eat = function () { alert("吃飯"); } this.sleep = function () { alert("睡覺"); } } //定義一個(gè)子類: 學(xué)生 //學(xué)生Student也是人,自然要繼承超類 Person 的所有屬性和方法 //學(xué)生都應(yīng)當(dāng)有姓名、年齡、會(huì)吃飯、會(huì)睡覺 //當(dāng)然學(xué)生也有自己的一些屬性:學(xué)號,學(xué)校名稱等,和方法,比如都要去做一件事:寫作業(yè) function Student (stuID, schoolName, name, age) { this.stuID = stuID; this.schoolName = schoolName; //用call調(diào)用 Person,以實(shí)現(xiàn)繼承 Person.call(this, name, age); } Student.prototype.doHomework = function () { alert("做作業(yè)"); } //實(shí)例化一個(gè)學(xué)生 var stu1 = new Student(1001, "第一小學(xué)", "王寶寶",20); console.log(stu1.stuID); //1001 console.log(stu1.schoolName); //"第一小學(xué)" console.log(stu1.name); //"王寶寶" console.log(stu1.age); //20 stu1.eat(); //"吃飯" stu1.sleep(); //"睡覺" stu1.doHomework(); //"做作業(yè)"
在子類構(gòu)造函數(shù)中,我們通過 call 的方式調(diào)用了父類構(gòu)造函數(shù) Person實(shí)現(xiàn)了繼承。別忘了,函數(shù)只不過是一段可以在特定作用域執(zhí)行代碼的特殊對象,我們可以通過 call 方法指定函數(shù)的作用域。
在 stu1 = new Student() 構(gòu)造函數(shù)時(shí),Student 內(nèi)部 this 的值指向的是 stu1, 所以 this.stuID =stu1.stuID, 所以 Person.call(this, name, age) 就相當(dāng)于Person.call(stu1, "王寶寶", 20),就相當(dāng)于 stu1.Person("王寶寶",20)。最后,stu1 去調(diào)用 Person 方法時(shí),Person 內(nèi)部的 this 指向就指向了 stu1。那么Person 內(nèi)部this 上的所有屬性和方法,都被拷貝到了stu1上。
總之,在子類函數(shù)中,通過call() 方法調(diào)用父類函數(shù)后,子類實(shí)例 stu1, 可以訪問到 Student 構(gòu)造函數(shù)和 Person 構(gòu)造函數(shù)里的所有屬性和方法。這樣就實(shí)現(xiàn)了子類向父類的繼承。
缺點(diǎn)這種形式的繼承,每個(gè)子類實(shí)例都會(huì)拷貝一份父類構(gòu)造函數(shù)中的方法,作為實(shí)例自己的方法,比如 eat()。這樣做,有幾個(gè)缺點(diǎn):
1. 每個(gè)實(shí)例都拷貝一份,占用內(nèi)存大,尤其是方法過多的時(shí)候。
2. 方法都作為了實(shí)例自己的方法,當(dāng)需求改變,要改動(dòng)其中的一個(gè)方法時(shí),之前所有的實(shí)例,他們的該方法都不能及時(shí)作出更新。只有后面的實(shí)例才能訪問到新方法。
所以,其實(shí)多帶帶使用原型鏈繼承或者借用構(gòu)造函數(shù)繼承都有自己很大的缺點(diǎn),最好的辦法是,將兩者結(jié)合一起使用,發(fā)揮各自的優(yōu)勢。
例如:
function OSTAccountDC() { OSTBaseDC.call(this); } OSTAccountDC.prototype = new OSTBaseDC(); //通過OSTBaseDC創(chuàng)建一個(gè)實(shí)例,避免改變父類構(gòu)造函數(shù)的屬性,而只是在本地創(chuàng)建一個(gè)屬性。 OSTAccountDC.prototype.constructor = OSTAccountDC; //使this指向自己OSTAccountDC,而不是指向構(gòu)造函數(shù)OSTBaseDC OSTAccountDC.prototype.accountRequest = function(callback){ // do something }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/93754.html
摘要:綜上所述有原型鏈繼承,構(gòu)造函數(shù)繼承經(jīng)典繼承,組合繼承,寄生繼承,寄生組合繼承五種方法,寄生組合式繼承,集寄生式繼承和組合繼承的優(yōu)點(diǎn)于一身是實(shí)現(xiàn)基于類型繼承的最有效方法。 一、前言 繼承是面向?qū)ο螅∣OP)語言中的一個(gè)最為人津津樂道的概念。許多面對對象(OOP)語言都支持兩種繼承方式::接口繼承 和 實(shí)現(xiàn)繼承 。 接口繼承只繼承方法簽名,而實(shí)現(xiàn)繼承則繼承實(shí)際的方法。由于js中方法沒有簽名...
摘要:想要解決這樣的問題的話,可以借助構(gòu)造函數(shù)也可以叫做偽造對象或經(jīng)典繼承。通過借助構(gòu)造函數(shù)實(shí)現(xiàn)對實(shí)例對象的屬性和繼承。 原型鏈 原型鏈?zhǔn)鞘裁?構(gòu)造函數(shù)或構(gòu)造器具有prototype屬性 對象具有__proto__屬性 這就是之前學(xué)習(xí)的原型如果構(gòu)造函數(shù)或?qū)ο驛 A的原型指向構(gòu)造函數(shù)或?qū)ο驜 B的原型在指向構(gòu)造函數(shù)或?qū)ο驝 以此類推 最終的構(gòu)造函數(shù)或?qū)ο蟮脑椭赶騉bject的原型 由此形成一...
摘要:在節(jié)中,我們學(xué)習(xí)到了通過構(gòu)造函數(shù)創(chuàng)建對象的三個(gè)重要步驟,其中的一步是把構(gòu)造函數(shù)的對象設(shè)置為創(chuàng)建對象的原型。利用而不是直接用創(chuàng)建一個(gè)實(shí)例對象的目的是,減少一次調(diào)用父構(gòu)造函數(shù)的執(zhí)行。 JavaScript語言不像面向?qū)ο蟮木幊陶Z言中有類的概念,所以也就沒有類之間直接的繼承,JavaScript中只有對象,使用函數(shù)模擬類,基于對象之間的原型鏈來實(shí)現(xiàn)繼承關(guān)系,ES6的語法中新增了class關(guān)鍵...
摘要:在使用原型鏈實(shí)現(xiàn)繼承時(shí)有一些需要我們注意的地方注意繼承后的變化。在了解原型鏈時(shí),不要忽略掉在末端還有默認(rèn)的對象,這也是我們能在所有對象中使用等對象內(nèi)置方法的原因。 在上一篇post中,介紹了原型的概念,了解到在javascript中構(gòu)造函數(shù)、原型對象、實(shí)例三個(gè)好基友之間的關(guān)系:每一個(gè)構(gòu)造函數(shù)都有一個(gè)守護(hù)神——原型對象,原型對象心里面也存著一個(gè)構(gòu)造函數(shù)的位置,兩情相悅,而實(shí)例呢卻又...
摘要:這正是我們想要的太棒了毫不意外的,這種繼承的方式被稱為構(gòu)造函數(shù)繼承,在中是一種關(guān)鍵的實(shí)現(xiàn)的繼承方法,相信你已經(jīng)很好的掌握了。 你應(yīng)該知道,JavaScript是一門基于原型鏈的語言,而我們今天的主題 -- 繼承就和原型鏈這一概念息息相關(guān)。甚至可以說,所謂的原型鏈就是一條繼承鏈。有些困惑了嗎?接著看下去吧。 一、構(gòu)造函數(shù),原型屬性與實(shí)例對象 要搞清楚如何在JavaScript中實(shí)現(xiàn)繼承,...
摘要:因?yàn)檫@造成了繼承鏈的紊亂,因?yàn)榈膶?shí)例是由構(gòu)造函數(shù)創(chuàng)建的,現(xiàn)在其屬性卻指向了為了避免這一現(xiàn)象,就必須在替換對象之后,為新的對象加上屬性,使其指向原來的構(gòu)造函數(shù)。這個(gè)函數(shù)接收兩個(gè)參數(shù)子類型構(gòu)造函數(shù)和超類型構(gòu)造函數(shù)。 最近一直在研究js面向?qū)ο?,原型鏈繼承是一個(gè)難點(diǎn),下面是我對繼承的理解以下文章借鑒自CSDN季詩筱的博客 原型鏈繼承的基本概念: ES中描述了原型鏈的概念,并將原型鏈作為實(shí)現(xiàn)...
閱讀 3748·2021-09-22 15:28
閱讀 1362·2021-09-03 10:35
閱讀 946·2021-09-02 15:21
閱讀 3551·2019-08-30 15:53
閱讀 3551·2019-08-29 17:25
閱讀 631·2019-08-29 13:22
閱讀 1613·2019-08-28 18:15
閱讀 2354·2019-08-26 13:57