摘要:因此,請慎重重寫原型繼承說到就不得說繼承,我們通過給上添加屬性和方法,就能使該構造函數所有的實例對象擁有屬性和方法。
本人博客:【www.xiabingbao.com】
在本文中,我們講解prototype的內容主要由:什么是prototype,prototype與函數之間的關系,prototype與實例對象之間的關系,使用proto實現一個簡單的繼承。
1. prototype的簡要介紹在javascript中,創建的每個函數天生都自帶著一個prototype屬性。這里我們要強調的是:這個prototype屬性是一個指針,指向一個對象,在這里,我們稱指向的這個看不到但確實存在的對象為原型對象。其實可以用下面一個簡單的例子來說明:
var proto = { name : "wenzi", age : 25 } function Person(){ } Person.prototype = proto;
這樣Person.protptype就指向到了proto,如果還有其他的引用(A)也指向到了proto,那么這個引用和Person.prototype就是相等的:A==Person.prototype;
prototype指向的這個對象是真實存在的,可能很多的同學對prototype屬性和原型對象有些混淆,我們在這里把原型對象叫做大SB。大SB與普通對象的一個不同之處就是,他也有一個天生的屬性:constructor,這個constructor重新指回到了函數。不過,既然大SB也是一個對象,那么它也是繼承于Object的,擁有Object所有的方法和屬性,比如toString()等。
大SB = { constructor : Person, say : function(){ return "hello world"; } }
那么現在我們就能得到兩個引用關系:
大SB = Person.prototype; // 原型對象 = 函數.prototype;
Person = 大SB.constructor(Person.prototype.constructor); // 函數 = 原型對象.constructor(函數.prototype.constructor)
從運行的代碼中,可以驗證我們的觀點,Person.prototype的類型是object,Person.prototype.constructor重新指回到了Person。
其實在實例對象中,也存在著一個屬性指向到大SB中:
var John = new Person(); 大SB = John.__proto__;
即 John.__proto__ 和 Person.prototype 指向的是同一個引用:John.__proto__==Person.prototype。
2. 對象實例和prototype中的屬性在構造函數能設置屬性和方法,在prototype中也能設置屬性和方法,那new出的對象使用的是哪個呢?我們來看一個例子:
function Person(){ this.name = "wenzi"; } Person.prototype.name = "bing"; Person.prototype.say = function(){ return "hello world"; } var John = new Person(); alert(John.name); // "wenzi" alert(John.say()); // "hello world"
從運行的結果我們可以看到,John.name輸出的是構造函數中的屬性值"wenzi",John.say()輸出的是"hello world"。這是因為,當讀取某個對象的屬性值時,會首先在實例對象中進行搜索,若搜索到則直接進行返回;若搜索不到則去原型對象中進行尋找。因此在使用John調用say()方法時是正確的,不會報錯。而且是進行了兩次的搜索。
雖然say()是掛載在prototype上,John也同樣能直接進行訪問。但是,我們不能直接對John.say進行修改從而影響prototype的say()方法,如下:
John.say = function(){ return "this has changed"; } John.say(); // "this has changed" var Tom = new Person(); Tom.say(); // "hello world"
從運行John.say()的結果來看,say()方法確實發生了變化。但是,當我們再new出一個新對象Tom時,Tom.say()返回的還是"hello world",這是為什么呢?
因為,對John.say()進行修改時,不是修改了prototype上的say(),而是給John這個實例對象添加了一個say()方法,從而屏蔽了prototype上的say()方法,由上面的尋找順序我們可以知道,若實例對象存在這個方法就直接返回了,不再去原型對象上尋找。而new出的新對象Tom在調用say()方法時,Tom自己是沒有say()方法的,只能去原型對象上尋找,因此返回的還是"hello world"。所以,對John.say進行修改時,不是修改了prototype上的say()方法,而是給John添加了實例方法,屏蔽掉了prototype上的方法而已。那如何才能修改prototype上的方法呢,好辦,直接在prototype上修改:
Person.prototype.say = function(){ return "wenzi"s blog"; }
這樣就能修改prototype的say()方法了。
3. 重寫prototype在上面的例子中,我們都是大部分給prototype添加屬性或方法,本來prototype指向的是大SB,若我們給prototype添加屬性或方法時,就是給大SB添加屬性或方法:
Person.prototype.name = "wenzi";
而大SB里其他的屬性和方法是不受影響的,constructor依然指回到Person。但是,若我們這樣寫:
Person.prototype = { name : "wenzi", say : function(){ return "my name is name" } }
就是對Person的prototype重寫了,讓prototype進行了重新的指向,本來Person.prototype指向的是大SB,可是現在卻指向了CTM,而CTM里也沒有constructor屬性指回到Person,若是想重新指回到Person,還得手動添加一個constructor屬性:
Person.prototype = { constructor : Person, // 重新指回到Person name : "wenzi", say : function(){ return "my name is name" } }
這樣就能手動構造出新的原型對象了,new出的實例對象也能使用這個prototype上的屬性和方法。
但是這里還存在一個問題,若之前已經有new出的實例對象,然后再修改Person.prototype,之前的實例對象是無法使用新的原型對象(CTM)上的屬性和方法的,因為之前的實例對象的__proto__指向的依然是大SB。因此,請慎重重寫prototype
4. 原型繼承說到prototype就不得說prototype繼承,我們通過給prototype上添加屬性和方法,就能使該構造函數所有的實例對象擁有屬性和方法。我們先來看下面的代碼:
function Father(){ this.name = "father"; this.age = 43; } Father.prototype.job = "Doctor"; Father.prototype.getName = function(){ return this.name; } function Son(){ this.name = "son"; } Son.prototype = new Father(); // Son的prototype指向Father的實例對象 var John = new Son(); for(var k in John){ console.log(k+" : "+john[k]); } /* 輸出結果: name : son age : 43 job : Doctor getName : function (){ return this.name; } */
從上面的例子中可以看到,Son的實例對象繼承了Father中所有的屬性和方法。當然,若Son的對象實例中存在的,還依然保留。不過Son原型中的屬性和方法是會被徹底覆蓋的。我們來分析一下這是為什么?
Son的prototype指向的是Father的一個實例,我們把這拆成兩步:
var father = new Father(); Son.prototype = father;
在實例father中既有name,age屬性,也有Father.prototype中的屬性和方法,我們對father循環看一下:
for(var k in father){ console.log(k, father[k]); } /* name father age 43 job Doctor getName Father.getName() */
由于constructor是不可枚舉的類型,在for~in循環里是輸出不了constructor的,其實father是這樣的:
father = { constructor : Father, name : father age : 43 job : Doctor getName : Father.getName() }
因此Son的prototype指向的就是上面father的內容。到此,Son的prototype中的constructor的指向也發生了改變,本來Son.prototype是指向到Son的,現在指向到了Father。即完全重寫了Son的prototype,重新指向了另一個引用。所以,我們就能知道為什么對象實例中的屬性能夠保存,而prototype中的會徹底被刪除了。
如果想給Son添加原型方法或屬性,那只能是在Son.prototype = new Father();之后進行添加:
Son.prototype = new Father(); Son.prototype.getJob = function(){ return this.job; }
這樣就能添加上getJob方法了。
到這里,會有人問,如果Son.prototype = Father.prototype會怎么樣呢?我們剛才也說了Father.prototype指向的是大SB,而大SB也是一個實例對象,是Object的一個實例,這就相當于:
Son.prototype == 大SB; // 指向了大SB
因此,如果是Son.prototype = Father.prototype的話,那么Son只能繼承到Father.prototype上的job和getName(),其他的屬性是獲取不到的。
5. 總結本文簡單的介紹了一下prototype,讓我們能對prototype有個淺顯的認識。當然,博主才疏學淺,文章里會有很多疏漏和不完善的地方,歡迎大家批評指正。
本人博客:【www.xiabingbao.com】
歡迎大家關注我的微信公眾號:wenzichel
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85740.html
摘要:在這其中我們就逃不開要討論繼承原型對象構造函數實例了。想要獲得某一類型的構造函數可以用來獲得,也可以對該屬性進行賦值操作。三上面就提到一點是指構造函數的原型對象,它是一個對象,它是構造函數的屬性。 原型鏈這一個話題,需要和很多概念一起講,才能串成一個比較系統的知識點。在這其中我們就逃不開要討論繼承、原型對象、構造函數、實例了。 一、構造函數 構造函數是一類特殊的函數,它的作用是用來生成...
摘要:組合方式實現繼承原型鏈構造函數喵喵喵汪汪汪與的唯一區別是多了這一句組合方式實現了對構造函數內和原型上所有屬性和方法的繼承,并且的實例對象之間也不會相互干擾。 前言 關于JavaScript繼承相關的定義和方法網上已經有很多解釋啦,本菜鳥就不抄抄寫寫惹人嫌了,本文主要探討三種基本的繼承方式并且給出優化方案。 正文 借助構造函數實現繼承 function Parent1() { ...
摘要:數組的構造函數是原型鏈的指向與其他除以外的構造函數相同,的也指向頂級原型對象,每一個數組都是的實例,都指向。實例對象查找構造函數原型對象的方法一般會把對象共有的屬性和方法都放在構造函數的原型對象上。 showImg(https://segmentfault.com/img/remote/1460000018998704?w=900&h=506); 閱讀原文 概述 在 JavaScr...
摘要:中的和是一門很靈活的語言,尤其是。即然是面向對象的編程語言,那也是不可或缺的。在中,永遠指向的是他的調用者。定義是存在于實例化后對象的一個屬性,并且指向原對象的屬性。我們在擴展的時候,同時父類也會有對應的方法,這很顯然是一個很嚴重的問題。 javascript中的this和new javascript是一門很靈活的語言,尤其是function。他即可以以面向過程的方式來用,比如: f...
摘要:綁定使用方式進行調用函數時,會發生構造函數的調用。先上圖,然后根據文字閱讀使用調用函數之后,該函數才作為構造函數進行調用,構造一個全新的對象賦值給,而對象的指向了的對象,的對象有一個屬性指向的構造函數這個就是的原型鏈,也是的特性。 javascript語言是在運行時前即進行編譯的,而this的綁定也是在運行時進行綁定的。也就是說,this實際上是在函數被調用時候發生綁定的,它指向什么完...
閱讀 3280·2023-04-26 02:09
閱讀 2574·2021-11-24 09:39
閱讀 3268·2021-11-16 11:52
閱讀 3614·2021-10-26 09:50
閱讀 2771·2021-10-08 10:05
閱讀 2456·2021-09-22 15:25
閱讀 3299·2019-08-30 13:14
閱讀 908·2019-08-29 17:06