prototype實現繼承

就那發表於2018-07-19

前言:相信很多小夥伴對js繼承都不太陌生,有很多實現方式,本文通過兩個小故事對使用prototype實現繼承來做一個簡單解釋。。。

一、有錢人的故事

大家都知道建構函式能通過new操作生成一個例項,他們之間通過__proto__建立一個類似父子的關係,這種關係說起來還是有點抽象,我們可以用一個比較形象的例子來說明一下,請看下面程式碼:

//建立一個有錢人的建構函式
function RichMan(name,age,sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
}

//有錢人的特徵是啥樣的呢,我們把有錢人的財產寫在prototype裡
RichMan.prototype.money = 100000000;//擁有一個億
RichMan.prototype.gold = 1000000;//還有一百萬克黃金

//有錢人的兒子 名字一定不能太俗
var son = new RichMan("撕蔥",30,"male");
複製程式碼

好,一個有錢人(RichMan)的例項son建立完成,接下來重點來了,這個son的名字叫什麼,今年多大了?我們列印son看下:

prototype實現繼承
嗯,名字,年齡,性別都有,那他是不是有錢人呢?我們們也定一個判斷是否為有錢人的標準吧:money > 1000000 || gold > 50000。所以看看son的money和gold是不是符合有錢人的標準:

function isRichMan(person) {
    if(person.money > 1000000 ||  person.gold > 50000) {
        return true;
    } else {
        return false;
    }
}

console.log(isRichMan(son)) //返回了true
複製程式碼

得到的結果是有錢人,但是son本身是沒有money和gold屬性的,怎麼就是有錢人了呢?這是因為雖然在son本身沒有money和gold,但是son的爸爸有。他爸的錢和黃金他都能用,所以結果就不必多說了~

例項怎麼能訪問建構函式的解釋可以看下我另外一篇文章簡話 prototype 和 _proto_

二、JS的故事上集 —— 拜師(實現繼承)

話說從前有一個小村莊,村上經常來小偷壞人,村民經常被欺負,於是請了兩個會武功的人來保護他們。一個年齡稍大叫Java會深厚的內功,另一個叫JS有一身強硬外功,他們倆一起抓小偷打壞人,而且還幫助村民做農活等等。在他們倆的保護下,村民安居樂業,過著幸福美滿的生活,當然村民也會給這他們付一些金錢犒勞,就稱為工資吧。

function Java(salary){
    //薪水
    this.salary = salary;
    //內功
    this.konfu_in = ["乾坤大挪移","獅吼功","易筋經"];
    //老婆 ^_^
    this.wife = 0;
}
//Java還會的技能
Java.prototype.jiandan = true; //內功煎蛋

function JS(salary){
    //薪水
    this.salary = salary;
    //外功
    this.konfu_out = ["降龍十八掌","七傷拳"];
    //老婆
    this.wife = 1;
}
//JS還會的技能
Java.prototype.picahi = true; //劈柴
複製程式碼

這樣過了很多年,因為Java練習的是內功,受傷了恢復時間比較長,有時候還會走火入魔。JS雖然練習的外功,身強體壯,但是因為還練習了七傷拳,時不時就會殺敵一千自傷七百,兩個人都挺辛苦。

於是JS請教Java能不能教他一些內功,他學會了再傳給自己的孩子jser,以後jser一個人就能做兩個人的活。但是Java對JS說我們門派功夫只傳內不傳外,JS說好辦,跟你兒子學(貌似沒有老婆,不好意思,他們造孩子不用老婆的)你會的你兒子都會。就相當於跟你學了,於是乎:

//拜師 把師父兒子的技能全部拿過來為我所用
var javaer = new Java(15);
JS.prototype = javaer;
複製程式碼

三、JS的故事中集 —— 歸位(重置constructor屬性)

JS把學的Java功夫教會給了jser,就試著考驗下jser的功力如何,雖然內外功夫都學會了,並且還會用內功煎雞蛋。但是卻不認識自己的爹了,像走火入魔似的,總是喊Java叫爹,而且本來會劈柴的現在也不會了,這可有點尷尬了:

var jser = new JS(10);
console.log(jser.wife) //1
console.log(jser.salary) //10
console.log(jser.jiandan) //true
console.log(jser.konfu_in.length) //3
console.log(jser.konfu_out.length) //2
console.log(jser.pichai) //undefined
複製程式碼

這是因為拜師結果的影響:因為自己的技能(prototype)被javaer完全替代了,所以原來的技能就沒有了,而javaer內部的constructor指向的是javaer自己的爸爸Java,因此jser的constructor就指向了Java。

console.log(jser.constructor === JS) //false
console.log(jser.constructor === Java) //true
複製程式碼

但是這個影響可以在拜師後再修改,就是把自己的技能的提供者強制指向自己,然後再新增相應的技能:

JS.prototype = new Java(15);
//把技能提供者再指向自己
JS.prototype.constructor = JS;
//然後再新增技能
JS.prototype.pichai = true;
var jser = new JS(10);
console.log(jser.pichai) //true
console.log(jser.constructor === JS) //true
console.log(jser.constructor === Java) //false
複製程式碼

於是jser不僅學會了父親JS的本領,也學會了父親師父Java的本領,並且也能清楚的找清自己的父親是誰,各種技能也不在話下,簡直太好了。。。

四、JS的故事下集 —— 使命(原型鏈只有一條)

因為jser的加入,JS和Java的工作變得倍加輕鬆。JS就準備外出去拜見更多的師父,學更多的本領。因為他聽說有個叫PHP的自稱天下第一,還有個叫Python的也是名聲在外,還有位老師傅叫C++涉獵頗豐、、、跟著這些人肯定能學會更多更強的本領。

江湖中的還有一條更重要的規矩必須要遵守:就是同時只能有一個師傅,也就是師承一脈(例項只能有一條往上的__proto__),要想跟新師傅就要脫離原來的門派,這樣才能實現傳承性。因此JS每拜一次師父就先把以前學的功夫廢掉,為了保留各種功夫,JS每次學一種新功夫就傳給自己的一個兒子:

//PHP大師
function PHP(salary) {
    this.salary = salary;
    this.konfu_in = ["化骨綿掌"];
}
PHP.prototype.say = "天下第一";
//師承 PHP
JS.prototype = new PHP();
JS.prototype.constructor = JS;
//jser2 同時擁有PHP的特性
var jser2 = new JS(10);
console.log(jser2.say) //天下第一
console.log(jser2 instanceof JS) //true
console.log(jser2 instanceof PHP) //true
console.log(jser2 instanceof Java) //false

//Python大師
function Python(salary) {
    this.salary = salary;
    this.konfu_py = ["催眠大法","卜掛"];
}
Python.prototype.say = "你知不知道我知道你不知道我知道你在想什麼?";
//師承 Python
JS.prototype = new Python();
JS.prototype.constructor = JS;
//jser3 同時擁有Python的特性
var jser3 = new JS(10);
console.log(jser3.say) //你知不知道我知道你不知道我知道你在想什麼?
console.log(jser3 instanceof JS) //true
console.log(jser3 instanceof Python) //true
.
.
.
複製程式碼

隨著JS拜師學了更多的本領後,年齡也逐漸老去,一天老JS把所有的孩子叫到身邊語重心長的對他們說:為父年事已老,有些話想告訴你們,其實我學那麼多本領並不是要為了證明什麼,我只是想讓你們知道我們JS的使命:“Any application that can be written in JavaScript, will eventually be written in JavaScript”。

jser們聽後若有所思的點點頭。。。

相關文章