原型位迂、原型鏈、繼承 | JavaScript

原型與原型鏈

基本概念

關(guān)于原型和原型鏈的知識详瑞,首先來理解下以下幾個知識點:

  1. 所有引用類型(Object掂林、ArrayFunction坝橡、Date泻帮、RegExp)都是對象。
    對象都有__proto__屬性计寇。

    image.png
  2. 所有構(gòu)造函數(shù)都有prototype屬性锣杂。

  3. prototype可以理解成一套模板,它用于保存一些方法番宁。
    其中:constructor是構(gòu)造器(創(chuàng)建當前對象的函數(shù))元莫, 也就是用來查看自己定義了什么構(gòu)造方法。

    image.png

  4. __proto__屬性的作用是溯源蝶押,指向構(gòu)造它的那個構(gòu)造函數(shù)的prototype踱蠢。
    (也就是說,可以用它來尋找到構(gòu)造它的那個構(gòu)造函數(shù)的模板是啥棋电。)

  5. prototype本身也是一個對象茎截,所以也有__proto__屬性苇侵。(也就是第一點提到的,所有對象都有__proto__屬性)

  6. Object是原始對象企锌,所以為了避免死循環(huán)榆浓,規(guī)定Object.prototype.__proto__會指向null
    nullundefined都沒有__proto__屬性了霎俩,即最高層哀军。

  7. ObjectFunction的關(guān)系有點像是雞和蛋的關(guān)系,所以

    Object.__proto__=== Function.__proto__ === Function.prototype
    Function.prototype.__proto__ === Object.prototype
    

例子說明

結(jié)合上面的基本概念打却,我們來看一下這個例子:

function Person(name) {
    this.name = name
}

const Lee = new Person('Lee')

Lee.__proto__ === Person.prototype // true
// ↑ 對應(yīng)第4點杉适,Lee的__proto__(溯源作用)指向構(gòu)造它的那個構(gòu)造函數(shù)(Person)的prototype
Person.__proto__ === Function.prototype // true
// ↑ Person的__proto__指向構(gòu)造它的構(gòu)造函數(shù)(Function)的prototype

Person.toString // ? toString() { [native code] }
// ↑ Person里面并沒有toString方法,但是卻可以引用到
// 因為繼承了Object的一套“模板” ↓↓↓
Person.prototype.__proto__ === Object.prototype

Object.prototype.__proto__ === null // 到達最頂層了柳击!

// 第3點提到猿推,prototype可以理解成一套模板,它用于保存一些方法捌肴。其中constructor是構(gòu)造器(創(chuàng)建當前對象的函數(shù))蹬叭,也就是用來查看自己定義了什么構(gòu)造方法。
// 所以:↓↓↓
Lee.constructor === Person // Lee的構(gòu)造方法是Person
Person.constructor === Object

// Object和Function的關(guān)系有點像是雞和蛋的關(guān)系
Function.prototype.__proto__ === Object.prototype // true
Object.__proto__ === Function.prototype

如果用圖片的形式來表現(xiàn)状知,就是下圖這樣:

image.png

繼承

原型鏈繼承

function Parent() {
    this.names = ['Debra', 'Patamo']
}
function Child() {}
Child.prototype = new Parent()
const child1 = new Child()
child1.names // ['Debra', 'Patamo']

缺點:

引用類型的屬性被所有實例共享秽五。

child1.names.push('Pikachu')
child1.names // ['Debra', 'Patamo', 'Pikachu']
const child2 = new Child()
child2.names // ['Debra', 'Patamo', 'Pikachu']

在創(chuàng)建 Child 的實例時,不能向Parent傳參饥悴。

借用構(gòu)造函數(shù)(經(jīng)典繼承)

function Parent() {
    this.names = ['Debra', 'Patamo']
}
function Child() {
    Parent.call(this)
}
const child1 = new Child();
child1.names.push('Pikachu');
console.log(child1.names); // ['Debra', 'Patamo', 'Pikachu']

const child2 = new Child();
console.log(child2.names); // ['Debra', 'Patamo']

優(yōu)點:

  1. 避免了引用類型的屬性被所有實例共享
  2. 可以在 Child 中向 Parent 傳參

缺點:

  1. 只能繼承父類的實例屬性和方法坦喘,不能繼承原型屬性/方法
  2. 無法實現(xiàn)復(fù)用,每個子類都有父類實例函數(shù)的副本西设,影響性能

組合繼承

function Parent() {
    this.name = 'Debra'
}
Parent.prototype.getName = function() { return this.name }
function Child() {
    Parent.call(this) // 繼承屬性
}
Child.prototype = new Parent() // 繼承方法

const child = new Child()
child.getName() // Debra

優(yōu)點:

  1. 彌補了原型鏈和結(jié)構(gòu)構(gòu)造函數(shù)的不足瓣铣,是JavaScript中使用最多的繼承模式。
  2. 保留了instanceof操作符和isPrototypeOf()方法識別合成對象的能力贷揽。

缺點:

調(diào)用了兩次父類構(gòu)造函數(shù)棠笑,影響性能。

一次是設(shè)置子類型實例的原型的時候:

Child.prototype = new Parent();

一次在創(chuàng)建子類型實例的時候:

var child1 = new Child();

回想下 new 的模擬實現(xiàn)禽绪,其實在這句中蓖救,我們會執(zhí)行:

Parent.call(this, name);

在這里,我們又會調(diào)用了一次 Parent 構(gòu)造函數(shù)丐一。

原型繼承

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

就是 ES5 Object.create 的模擬實現(xiàn)藻糖,將傳入的對象作為創(chuàng)建的對象的原型。

缺點:

包含引用類型的屬性值始終都會共享相應(yīng)的值库车,這點跟原型鏈繼承一樣巨柒。

var person = {
    name: 'kevin',
    friends: ['daisy', 'kelly']
}

var person1 = createObj(person);
var person2 = createObj(person);

person1.name = 'person1';
console.log(person2.name); // kevin

person1.friends.push('taylor');
console.log(person2.friends); // ["daisy", "kelly", "taylor"]

注意:修改person1.name的值,person2.name的值并未發(fā)生改變,并不是因為person1person2有獨立的 name 值洋满,而是因為person1.name = 'person1'晶乔,給person1添加了 name 值,并非修改了原型上的 name 值牺勾。

寄生式繼承

創(chuàng)建一個僅用于封裝繼承過程的函數(shù)正罢,該函數(shù)在內(nèi)部以某種形式來做增強對象,最后返回對象驻民。

function createObj (o) {
    var clone = Object.create(o); // 重點
    clone.sayName = function () {
        console.log('hi');
    }
    return clone;
}

缺點:跟借用構(gòu)造函數(shù)模式一樣翻具,每次創(chuàng)建對象都會創(chuàng)建一遍方法。

****寄生組合式繼承(最佳)****

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

function prototype(child, parent) {
    let prototype = object(parent.prototype)
    prototype.constructor = child
    child.prototype = prototype
}

優(yōu)點:

  1. 只調(diào)用了一次 Parent 構(gòu)造函數(shù)回还,并且因此避免了在 Parent.prototype 上面創(chuàng)建不必要的裆泳、多余的屬性。
  2. 原型鏈還能保持不變柠硕;因此工禾,還能夠正常使用 instanceof 和 isPrototypeOf。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蝗柔,一起剝皮案震驚了整個濱河市闻葵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌癣丧,老刑警劉巖槽畔,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異胁编,居然都是意外死亡竟痰,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門掏呼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人铅檩,你說我怎么就攤上這事憎夷。” “怎么了昧旨?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵拾给,是天一觀的道長。 經(jīng)常有香客問我兔沃,道長蒋得,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任乒疏,我火速辦了婚禮额衙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己窍侧,他們只是感情好县踢,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著伟件,像睡著了一般硼啤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上斧账,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天谴返,我揣著相機與錄音,去河邊找鬼咧织。 笑死嗓袱,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的拯爽。 我是一名探鬼主播索抓,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼毯炮!你這毒婦竟也來了逼肯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤桃煎,失蹤者是張志新(化名)和其女友劉穎篮幢,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體为迈,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡三椿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了葫辐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搜锰。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖耿战,靈堂內(nèi)的尸體忽然破棺而出蛋叼,到底是詐尸還是另有隱情,我是刑警寧澤剂陡,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布狈涮,位于F島的核電站,受9級特大地震影響鸭栖,放射性物質(zhì)發(fā)生泄漏歌馍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一晕鹊、第九天 我趴在偏房一處隱蔽的房頂上張望松却。 院中可真熱鬧暴浦,春花似錦、人聲如沸玻褪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽带射。三九已至同规,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間窟社,已是汗流浹背券勺。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留灿里,地道東北人关炼。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像匣吊,于是被迫代替她去往敵國和親儒拂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

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