摘要:原型鏈上有兩個(gè)關(guān)鍵詞和比較重要,是設(shè)置構(gòu)造函數(shù)的原型對(duì)象,是聲明原型的構(gòu)造函數(shù),不管是對(duì)象還是函數(shù),都有一個(gè)隱式屬性用來構(gòu)成一條完整原型鏈的指向。
思考
說到原型,不得不提到原型鏈,js中不管是對(duì)象還是方法(也是對(duì)象)都有個(gè)隱藏屬性_proto_,來表示原型鏈的下一個(gè)指向,一般對(duì)象是指向Object.prototype,方法是指向Function.prototype,構(gòu)造函數(shù)new出來的對(duì)象指向想構(gòu)造函數(shù)的prototype原型鏈的思考
因?yàn)樵玩湹拇嬖?,?dāng)前對(duì)象或者方法可以共用原型鏈上的上級(jí)屬性和方法
var obj = {}; obj.toString() //[object Object]
obj對(duì)象上是沒有toString方法的,因?yàn)閛bj._proto_指向Object.prototype,具體上是調(diào)用Object.prototype方法:Object.prototype.toString.apply(obj)
function Foo() { } Foo.toString();//function Foo() {}
方法的原型鏈?zhǔn)荈oo->Function.prototype->Object.prototype,所以Foo調(diào)用toString方法是引用Function上的toString方法,具體上是調(diào)用Function.prototype方法:Function.prototype.toString.apply(obj)
有時(shí)候我們?yōu)榱死^承父類(其實(shí)js并沒有類這個(gè)概念),會(huì)通過原型繼承去繼承父類的一些方法,在此之前,先簡(jiǎn)單敘述下通過構(gòu)造函數(shù)實(shí)例化一個(gè)對(duì)象的過程,比如以下創(chuàng)建一個(gè)obj對(duì)象,
var obj = new Object();
先創(chuàng)建一個(gè)空對(duì)象{}
空對(duì)象{}._proto_指向Object.prototype
Object.apply({})
再執(zhí)行構(gòu)造方法里面的代碼
所以當(dāng)es5繼承方法時(shí),可以選擇原型繼承,通過修改prototype的值,如:
ES5的情況:
var Father = function(name) { this.name = name; } Father.prototype.say = function() { return "my name is " + this.name; } var Child = function(name) { this.name = name; } Child.prototype = new Father(); var child = new Child("Nico"); child.say();//my name is Nico
但是在上面原型繼承的情況,我們還要對(duì)Child的構(gòu)造函數(shù)的constructor做一個(gè)聲明
Child.prototype.constructor = Child;
因?yàn)镃hild原型是Father實(shí)例的一個(gè)引用,當(dāng)想修改Child原型的方法時(shí),會(huì)被掛在Father的實(shí)例對(duì)象上。
ES6的情況:
class Father { constructor(name) { this.name = name; } say() { return "my name is " + this.name; } } class Child extends Father { constructor(name) { super(name) } } var child = new Child("Nico"); child.say()//my name is Nico
es6的class類中,Child類的原型構(gòu)造器不用做額外聲明,因?yàn)?,es6的class的constructor指向自身
繼承的思考子類能使用父類的方法
除了上面提及到的原型鏈繼承,還有例如構(gòu)造函數(shù)繼承:
function Veticle(name) { this.name = name || null this.drive = function() { console.log(this.name + " drives! --from Veticle "); } } function Car(name) { Veticle.call(this) this.name = name; } var car = new Car("a car"); car.drive();//a car drives! --from Veticle
這種方法核心就通過改變構(gòu)造函數(shù)的上下文(context),達(dá)到子類能夠使用父類方法,但是這種方法不能使用父類原型方法。
除此之外,還可以遍歷父類實(shí)例繼承父類方法:
function Veticle(name) { this.name = name || null this.drive = function() { console.log(this.name + "drives! --from Veticle "); } } Veticle.prototype.getName = function() { return this.name; } function Car(name) { var veticle = new Veticle(); for (var p in veticle) { console.log(p) Car.prototype[p] = veticle[p]; } this.name = name; } var car = new Car("a car"); car.getName();//a car
這種方法可以獲取實(shí)例能調(diào)用的所有方法,除了不可枚舉(ES6 class方法是不可枚舉的)
其實(shí)關(guān)于繼承js已經(jīng)有個(gè)很好的的實(shí)現(xiàn)方法叫寄生組合繼承,大概原理是用構(gòu)造函數(shù)繼承實(shí)例屬性,用原型繼承原型方法,而寄生組合繼承是在組合繼承的基礎(chǔ)上強(qiáng)化,兩者的區(qū)別是前者避免了兩次實(shí)例化父類,是目前比較好的es5實(shí)現(xiàn)繼承的方法:
function Veticle(name) { this.name = name || null this.drive = function() { console.log(this.name + "drives! --from Veticle "); } } Veticle.prototype.getName = function() { return this.name; } function Car(name) { Veticle.call(this) this.name = name || "car" } function inheritProto(subType, superType) { var prototype = Object.create(superType.prototype); subType.prototype.constructor = subType; subType.prototype = prototype; } inheritProto(Car, Veticle) var car = new Car("siip");總結(jié)
????js中有一些構(gòu)造方法諸如Object、Function、String、Number等等,當(dāng)當(dāng)前對(duì)象調(diào)用方法或獲取屬性時(shí),會(huì)順著自身對(duì)象到構(gòu)造函數(shù)原型,再到Object原型,最后到Null這么一條原型鏈上查找。原型鏈上有兩個(gè)關(guān)鍵詞prototype和constructor比較重要,prototype是設(shè)置構(gòu)造函數(shù)的原型對(duì)象,constructor是聲明原型的構(gòu)造函數(shù),不管是對(duì)象還是函數(shù),都有一個(gè)隱式屬性_proto_用來構(gòu)成一條完整原型鏈的指向。
????繼承有繼承屬性和繼承方法,很多時(shí)候es5實(shí)現(xiàn)繼承比es6要稍微簡(jiǎn)單一點(diǎn),es6的class的原型方法是不可枚舉的,有時(shí)候,掛載方法時(shí)需要通過Object.getOwnPropertyNames方法獲取。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93932.html
摘要:面向?qū)ο笾玩湆?duì)象和對(duì)象之間的關(guān)系注意這個(gè)系列文章要經(jīng)常站在之父的視角去思考。思考問題我們都知道都屬于那么既然他們都是對(duì)象一定有某些相同之處吧對(duì)象和對(duì)象之間有什么關(guān)聯(lián)呢如果說你沒有思考過這個(gè)問題那么可以換一個(gè)更具體的問題。 JS面向?qū)ο笾?【原型鏈】(對(duì)象和對(duì)象之間的關(guān)系) 注意這個(gè)系列文章,要經(jīng)常站在JS之父的視角去思考。 牢記我們的需求,我要在JS沒有class的情況下,那么...
摘要:構(gòu)造函數(shù),實(shí)例構(gòu)造函數(shù),是用來創(chuàng)建對(duì)象的函數(shù),本質(zhì)上也是函數(shù)。這里剛好解釋一下時(shí),說到的,可以通過實(shí)例的訪問構(gòu)造函數(shù),但是本質(zhì)上是原型對(duì)象的屬性。 前言 最近在學(xué)vue,到周末終于有空寫一些東西了(想想又能騙贊,就有點(diǎn)小激動(dòng)?。T趈avascript基礎(chǔ)中,除了閉包之外,繼承也是一個(gè)難點(diǎn)。因?yàn)榭紤]到篇幅較長(zhǎng),所以打算分成兩個(gè)部分來寫。同樣基于《javascript高級(jí)程序設(shè)計(jì)》,做一...
摘要:但是,中并沒有類的概念,而是通過構(gòu)造函數(shù)替代了類的功能,為某一類的對(duì)象提供共同的屬性和方法。一只名叫的狗,首先繼承了構(gòu)造函數(shù)的原型對(duì)象,而的原型對(duì)象中的有繼承了函數(shù)的原型對(duì)象,函數(shù)對(duì)象中的有繼承了的原型對(duì)象。 《圣經(jīng)》里的第一章創(chuàng)世紀(jì)中其中有一段經(jīng)典記載上帝是如何創(chuàng)造人的。神說:我們要照著我們的形象,按照我們的樣式造人。不謀而合的是,JavaScript中似乎也遵循著上帝的旨意去創(chuàng)造程...
摘要:代碼傳送門如上代碼示例,從其運(yùn)行結(jié)果可知,是等于的原型的,是被對(duì)象后返回的函數(shù),從驗(yàn)證結(jié)果來看,函數(shù)經(jīng)過的一層包裝,依然不會(huì)影響其原型檢測(cè)的綁定。前言 在面向?qū)ο笳Z言中,一般都有關(guān)鍵字 instanceof 來檢測(cè)對(duì)象類型,更準(zhǔn)確點(diǎn)來說是檢測(cè)對(duì)象是哪個(gè)類型的實(shí)例。那么在 JS 中這個(gè)關(guān)鍵字又有什么不同之處呢?此文僅是一篇對(duì) ES 標(biāo)準(zhǔn)中 instanceof 關(guān)鍵字的解讀,并記錄了在此過程中...
摘要:并嘗試用為什么你統(tǒng)計(jì)的方式是錯(cuò)的掘金翻譯自工程師的文章。正如你期望的,文中的前端開發(fā)單一職責(zé)原則前端掘金單一職責(zé)原則又稱單一功能原則,面向?qū)ο笪鍌€(gè)基本原則之一。 單頁式應(yīng)用性能優(yōu)化 - 首屏數(shù)據(jù)漸進(jìn)式預(yù)加載 - 前端 - 掘金前言 針對(duì)首頁和部分頁面打開速度慢的問題,我們開始對(duì)單頁式應(yīng)用性能進(jìn)行優(yōu)化。本文介紹其中一個(gè)方案:基于 HTTP Chunk 的首屏數(shù)據(jù)漸進(jìn)式預(yù)加載方案,該方案總...
閱讀 3031·2021-11-24 10:21
閱讀 1602·2021-10-11 10:57
閱讀 2814·2021-09-22 15:24
閱讀 2678·2021-09-22 14:58
閱讀 2337·2019-08-30 13:16
閱讀 3489·2019-08-29 13:05
閱讀 3422·2019-08-29 12:14
閱讀 3461·2019-08-27 10:55