19_怎么理解js中的原型鏈尖啡?如何實(shí)現(xiàn)繼承?實(shí)現(xiàn)繼承常用的方式有哪些

一盆顾、理解js的原型

1畏梆、函數(shù)和對象的關(guān)系

函數(shù)也是對象的一種,通過instanceof可以判斷出來宪巨。但是函數(shù)和對象的關(guān)系并不是簡單的包含和被包含的關(guān)系

對象都是通過函數(shù)創(chuàng)建的

var obj = {a:10,b:20};
var arr = [5, 'x', true];

但是溜畅,其實(shí)上面這段代碼的實(shí)質(zhì)是下面這樣的:

//var obj = { a: 10, b: 20 };
//var arr = [5, 'x', true];

 var obj = new Object();
 obj.a = 10;
 obj.b = 20;

 var arr = new Array();
 arr[0] = 5;
 arr[1] = 'x';
 arr[2] = true;

而Object和Array都是函數(shù)捏卓,可以自己用typeof函數(shù)進(jìn)行驗(yàn)證怠晴。

所以浴捆,可以得出:對象都是通過函數(shù)創(chuàng)建的

2、原型prototype

在前言中冲粤,我們說了函數(shù)也是一種對象,所以函數(shù)也是屬性的集合色解,同時(shí)科阎,也可以對函數(shù)進(jìn)行自定義屬性忿族。
每個(gè)函數(shù)都有一個(gè)屬性——prototype。這個(gè)prototype的屬性值是一個(gè)對象(屬性的集合)错英,默認(rèn)只有一個(gè)叫做constructor的屬性隆豹,指向這個(gè)函數(shù)本身。 如下圖所示:

上圖中判哥,SuperType是一個(gè)函數(shù)塌计,右側(cè)的方框就是它的原型侯谁。

原型既然作為對象(屬性的集合),除了constructor外热芹,還可以自定義許多屬性惨撇,比如下面這樣的:

當(dāng)然了串纺,我們也可以在自己定義的方法的prototype中增加我們自己的屬性,比如像下面這樣的:

function Fn() { }
    Fn.prototype.name = '張三';
    Fn.prototype.getAge = function () {
       return 12;
};

那么問題來了:函數(shù)的prototype到底有何用呢?

在解決這個(gè)問題之前祷蝌,我們還是先來看下另一個(gè)讓人迷糊的屬性:_proto_

3、“隱式原型”proto

我們先看一段非常常見的代碼:

function Fn() { }
   Fn.prototype.name = '張三';
    Fn.prototype.getAge = function () {
       return 12;
};
var fn = new Fn();
console.log(fn.name);
console.log(fn.getAge ());

即米丘,F(xiàn)n是一個(gè)函數(shù)拄查,fn對象是從Fn函數(shù)new出來的,這樣fn對象就可以調(diào)用Fn.prototype中的屬性碍脏。

但是稍算,因?yàn)槊總€(gè)對象都有一個(gè)隱藏的屬性——“proto”,這個(gè)屬性引用了創(chuàng)建這個(gè)對象的函數(shù)的prototype钾埂。即:fn.proto === Fn.prototype
那么科平,這里的proto到底是什么呢匠抗?

其實(shí),這個(gè)proto是一個(gè)隱藏的屬性绳军,javascript不希望開發(fā)者用到這個(gè)屬性值矢腻,有的低版本瀏覽器甚至不支持這個(gè)屬性值。

var obj = {};
console.log(obj.__proto__);
console.log(Object.prototype);

從上面來看,obj.proto和Object.prototype的屬性一樣竣灌!為什么呢初嘹?

原因是:obj這個(gè)對象本質(zhì)上是被Object函數(shù)創(chuàng)建的,因此obj.proto=== Object.prototype坷随。我們可以用一個(gè)圖來表示。

即缸匪,每個(gè)對象都有一個(gè)proto屬性类溢,指向創(chuàng)建該對象的函數(shù)的prototype豌骏。

說一下自定義函數(shù)的prototype:
自定義函數(shù)的prototype本質(zhì)上就是和 var obj = {} 是一樣的,都是被Object創(chuàng)建,所以它的proto指向的就是Object.prototype钦睡。

但是荞怒,Object.prototype確實(shí)一個(gè)特例——它的proto指向的是null。

另外一個(gè)問題:函數(shù)也是一種對象衰抑,函數(shù)也有proto嗎荧嵌?
答:當(dāng)然也不例外啦啦撮!
下面用一段代碼和一張圖來說明這個(gè)問題,看完相信就有個(gè)比較直觀的理解啦愉择!

function fn(x, y) {
        return x+y;
}
console.log(fn(10,20));

//以下只是為了演示函數(shù)被Function創(chuàng)建的
var fn1 = new Function("x","y","return x+y;");
console.log(fn1(5,6));

用圖表示就是:

從上圖可以看出:自定義函數(shù)Foo.proto指向Function.prototype织中,Object.proto指向Function.prototype狭吼。

但是,為什么有Function.proto指向Function.prototype呢窿春?
其實(shí)原因很簡單:Function也是一個(gè)函數(shù),函數(shù)是一種對象蔚润,也有proto屬性尺栖。既然是函數(shù),那么它一定是被Function創(chuàng)建除盏。所以Function是被自身創(chuàng)建的挫以。所以它的proto指向了自身的Prototype

最后一個(gè)問題:Function.prototype指向的對象掐松,它的proto是不是也指向Object.prototype?
答案是肯定的抡句。因?yàn)镕unction.prototype指向的對象也是一個(gè)普通的被Object創(chuàng)建的對象杠愧,所以也遵循基本的規(guī)則。如下圖:

說了這么多锐锣,我們將上面這些圖片整合到一整個(gè)圖片刺下,便于整體理解稽荧,圖片如下:

4姨丈、instanceof

主要是說明下instanceof的判斷規(guī)則是如何進(jìn)行的。先看如下代碼和圖片:

function fn() {
}
var f1 = new fn();

console.log(f1 instanceof fn);//true
console.log(f1 instanceof Object);//true

instanceof的判斷規(guī)則為:
假設(shè)instanceof運(yùn)算符的第一個(gè)變量是一個(gè)對象翁潘,暫時(shí)稱為A拜马;第二個(gè)變量一般是一個(gè)函數(shù),暫時(shí)稱為B旺坠。

instanceof的判斷規(guī)則是:沿著A的proto這條線來找扮超,同時(shí)沿著B的prototype這條線來找,如果兩條線能找到同一個(gè)引用璧疗,即同一個(gè)對象馁龟,那么就返回true恭垦。如果找到終點(diǎn)還未重合淌喻,則返回false裸删。

結(jié)合這個(gè)判斷規(guī)則阵赠,上面的代碼和圖示相信很容易看懂了。

二匕荸、原型繼承

原型鏈的定義:訪問一個(gè)對象的屬性時(shí)枷邪,先在基本屬性中查找东揣,如果沒有,再沿著proto這條鏈向上找尔觉,這就是原型鏈芥吟。

示例:在實(shí)際應(yīng)用中如何區(qū)分一個(gè)屬性到底是基本的還是從原型中找到的呢专甩?
答案就是:hasOwnProperty這個(gè)函數(shù)涤躲,特別是在for…in…循環(huán)中嫁盲,一定要注意。

但是8淄小俐镐!f1本身并沒有hasOwnProperty這個(gè)方法哺哼,那是從哪里來的呢取董?答案很簡單,是從Object.prototype中來的枢里□逦纾看下圖:

對象的原型鏈?zhǔn)茄刂?strong>proto這條線走的,因此在查找f1.hasOwnProperty屬性時(shí)奥洼,就會(huì)順著原型鏈一直查找到Object.prototype灵奖。

由于所有對象的原型鏈都會(huì)找到Object.prototype搬泥,因此所有對象都會(huì)有Object.prototype的方法。這就是所謂的“繼承”尉尾。

三燥透、原型繼承的幾種方式

  • 原型鏈繼承
  • 構(gòu)造函數(shù)繼承(對象冒充繼承)
  • 組合繼承(原型鏈繼承+構(gòu)造函數(shù)繼承)
  • 原型式繼承
  • 寄生組合式繼承

1、原型鏈繼承

function Show(){
    this.name="run";
}

function Run(){
    this.age="20"; //Run繼承了Show,通過原型故河,形成鏈條
}
Run.prototype=new Show();
var show=new Run();
console.log(show.name)//結(jié)果:run

2吆豹、構(gòu)造函數(shù)繼承(對象冒充繼承)

為了解決引用共享和超類型無法傳參的問題,我們采用一種叫借用構(gòu)造函數(shù)的技術(shù)凑阶,或者成為對象冒充(偽造對象衷快、經(jīng)典繼承)的技術(shù)來解決這兩種問題

function Box(age){
    this.name=['Lee','Jack','Hello']
    this.age=age;
}
function Desk(age){
    Box.call(this,age); //對象冒充蘸拔,給超類型傳參
}
var desk = new Desk(200);
console.log(desk.age);//200
console.log(desk.name);//['Lee','Jack','Hello']
desk.name.push('AAA'); //添加的新數(shù)據(jù),只給 desk
console.log(desk.name)//['Lee','Jack','Hello','AAA']

3宝冕、組合繼承(原型鏈繼承+構(gòu)造函數(shù)繼承)

借用構(gòu)造函數(shù)雖然解決了剛才兩種問題邓萨, 但沒有原型先誉, 復(fù)用則無從談起的烁。 所以渴庆, 我們需要原型鏈+借用構(gòu)造函數(shù)的模式,這種模式成為組合繼承刃滓。

function Box(age) {
    this.name = ['Lee', 'Jack', 'Hello']
    this.age = age;
}
Box.prototype.run = function () {
    return this.name + this.age;
};
function Desk(age) {
    Box.call(this, age); //對象冒充
}
Desk.prototype = new Box(); //原型鏈繼承
var desk = new Desk(100);
console.log(desk.run()); //Lee,Jack,Hello100

4耸弄、原型式繼承

這種繼承借助原型并基于已有的對象創(chuàng)建新對象计呈,
同時(shí)還不必因此創(chuàng)建自定義類型

function obj(o) { //傳遞一個(gè)字面量函數(shù)
    function F() {} //創(chuàng)建一個(gè)構(gòu)造函數(shù)
    F.prototype = o; //把字面量函數(shù)賦值給構(gòu)造函數(shù)的原型
    return new F(); //最終返回出實(shí)例化的構(gòu)造函數(shù)
}
var box = { //字面量對象
    name : 'Lee',
    arr : ['哥哥','妹妹','姐姐']
};
var box1 = obj(box); //傳遞
console.log(box1.name); // Lee
box1.name = 'Jack';
console.log(box1.name); // Jack
console.log(box1.arr); // (3) ["哥哥", "妹妹", "姐姐"]
box1.arr.push('父母');
console.log(box1.arr); // (4) ["哥哥", "妹妹", "姐姐", "父母"]
var box2 = obj(box); //傳遞
console.log(box2.name); // Lee
console.log(box2.arr); //引用類型共享了 (4) ["哥哥", "妹妹", "姐姐", "父母"]

5征唬、寄生組合式繼承

寄生組合式繼承解決了兩次調(diào)用的問題茁彭,組合式繼承就會(huì)有兩次調(diào)用的情況

基本模型如下:

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

function inheritPrototype(subType, superType) {
    var prototype = object(superType.prototype);  //創(chuàng)建對象
    prototype.constructor = subType;              //增強(qiáng)對象
    subType.prototype = prototype;                //指定對象
}

四理肺、參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末年枕,一起剝皮案震驚了整個(gè)濱河市画切,隨后出現(xiàn)的幾起案子囱怕,更是在濱河造成了極大的恐慌,老刑警劉巖典格,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件耍缴,死亡現(xiàn)場離奇詭異挽霉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蚁趁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門他嫡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來庐完,“玉大人门躯,你說我怎么就攤上這事∧瘢” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵饱须,是天一觀的道長蓉媳。 經(jīng)常有香客問我锅铅,道長,這世上最難降的妖魔是什么玩荠? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任阶冈,我火速辦了婚禮塑径,結(jié)果婚禮上统舀,老公的妹妹穿的比我還像新娘。我一直安慰自己碉就,他們只是感情好闷串,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布窿克。 她就那樣靜靜地躺著毛甲,像睡著了一般玻募。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上跃惫,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天爆存,我揣著相機(jī)與錄音,去河邊找鬼携冤。 笑死闲勺,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的翘地。 我是一名探鬼主播衙耕,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼序芦,長吁一口氣:“原來是場噩夢啊……” “哼谚中!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起宪塔,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤某筐,失蹤者是張志新(化名)和其女友劉穎南誊,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體霉赡,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡穴亏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年嗓化,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刺覆。...
    茶點(diǎn)故事閱讀 38,809評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡严肪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出隅津,到底是詐尸還是另有隱情诬垂,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布伦仍,位于F島的核電站结窘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏充蓝。R本人自食惡果不足惜隧枫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一谓苟、第九天 我趴在偏房一處隱蔽的房頂上張望官脓。 院中可真熱鬧,春花似錦涝焙、人聲如沸卑笨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赤兴。三九已至,卻和暖如春隧哮,著一層夾襖步出監(jiān)牢的瞬間桶良,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工沮翔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留陨帆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓采蚀,卻偏偏與公主長得像疲牵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子榆鼠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容