亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript 原型繼承之精髓

xingqiba / 2335人閱讀

摘要:它的原型也是對(duì)象。只要你完全拋開(kāi)面向?qū)ο蟮睦^承思路來(lái)看的原型繼承,你會(huì)發(fā)現(xiàn)它輕便但強(qiáng)大。最后寫(xiě)出來(lái)的代碼會(huì)是這樣請(qǐng)注意,只有函數(shù)才有屬性,它是用來(lái)做原型繼承的必需品。

一篇文章讓你搞清楚 JavaScript 繼承的本質(zhì)、prototype__proto__、constructor 都是什么。

很多小伙伴表示不明白 JavaScript 的繼承,說(shuō)是原型鏈,看起來(lái)又像類(lèi),究竟是原型還是類(lèi)?各種 prototype、__proto__constructor 內(nèi)部變量更是傻傻搞不清楚。其實(shí),只要明白繼承的本質(zhì)就很能理解,繼承是為了代碼復(fù)用。復(fù)用并不一定得通過(guò)類(lèi),JS 就采用了一種輕量簡(jiǎn)明的原型方案來(lái)實(shí)現(xiàn)。Java/C++ 等強(qiáng)類(lèi)型語(yǔ)言中有類(lèi)和對(duì)象的區(qū)別,但 JS 只有對(duì)象。它的原型也是對(duì)象。只要你完全拋開(kāi)面向?qū)ο蟮睦^承思路來(lái)看 JS 的原型繼承,你會(huì)發(fā)現(xiàn)它輕便但強(qiáng)大。

目錄

繼承方案的設(shè)計(jì)要求

被復(fù)用的對(duì)象:prototype

優(yōu)雅的 API:ES6 class

簡(jiǎn)明的向上查找機(jī)制:__proto__

構(gòu)造函數(shù)又是個(gè)啥玩意兒

雙鏈合璧:終極全圖

總結(jié)

參考

繼承方案的設(shè)計(jì)要求

前面我們講,繼承的本質(zhì)是為了更好地實(shí)現(xiàn)代碼復(fù)用。再仔細(xì)思考,可以發(fā)現(xiàn),這里的「代碼」指的一定是「數(shù)據(jù)+行為」的復(fù)用,也就是把一組數(shù)據(jù)和數(shù)據(jù)相關(guān)的行為進(jìn)行封裝。為什么呢?因?yàn)椋绻皇菑?fù)用行為,那么使用函數(shù)就足夠了;而如果只是復(fù)用數(shù)據(jù),這使用 JavaScript 對(duì)象就可以了:

const parent = {
  some: "data",
}
const child = {
  ...parent,
  uniq: "data",
}

因此,只有數(shù)據(jù)+行為(已經(jīng)類(lèi)似于一個(gè)「對(duì)象」的概念)的封裝,才是繼承技術(shù)所必須出現(xiàn)的地方。為了滿(mǎn)足這樣的代碼復(fù)用,一個(gè)繼承體系的設(shè)計(jì)需要支持什么需求呢?

存儲(chǔ)公用的數(shù)據(jù)和函數(shù)

覆蓋被繼承對(duì)象數(shù)據(jù)或函數(shù)的能力

向上查找/調(diào)用被繼承對(duì)象函數(shù)的數(shù)據(jù)或函數(shù)的能力

優(yōu)雅的語(yǔ)法(API)

增加新成員的能力

支持私有數(shù)據(jù)

「支持私有數(shù)據(jù)」,這個(gè)基本所有方案都沒(méi)實(shí)現(xiàn),此階段我們可以不用糾結(jié);而「增加新成員的能力」,基本所有的方案都能做到,也不再贅述,主要來(lái)看前四點(diǎn)。

被復(fù)用的對(duì)象:prototype

JavaScript 的繼承有多種實(shí)現(xiàn)方式,具體有哪些,推薦讀者可閱讀:[JavaScript 語(yǔ)言精粹][]一書(shū) 和 這篇文章。這里,我們直接看一版比較優(yōu)秀的實(shí)現(xiàn):

function Animal(name) {
  this.name = name
  this.getName = function() {
    return this.name
  }
}

function Cat(name, age) {
  Animal.call(this, name)
  this.age = age || 1
  this.meow = function() {
    return `${this.getName()}eowww~~~~~, I"m ${this.age} year(s) old`
  }
}

const cat = new Cat("Lily", 2)
console.log(cat.meow()) // "Lilyeowww~~~~~, I"m 2 year(s) old"

這個(gè)方案,具備增添新成員的能力、調(diào)用被繼承對(duì)象函數(shù)的能力等。一個(gè)比較重大的缺陷是:對(duì)象的所有方法 getName meow,都會(huì)隨每個(gè)實(shí)例生成一份新的拷貝。這顯然不是優(yōu)秀的設(shè)計(jì)方案,我們期望的結(jié)果是,繼承自同一對(duì)象的子對(duì)象,其所有的方法都共享自同一個(gè)函數(shù)實(shí)例。

怎么辦呢?想法也很簡(jiǎn)單,就是把它們放到同一個(gè)地方去,并且還要跟這個(gè)「對(duì)象」關(guān)聯(lián)起來(lái)。如此一想,用來(lái)生成這個(gè)「對(duì)象」的函數(shù)本身就是很好的地方。我們可以把它放在函數(shù)的任一一個(gè)變量上,比如:

Animal.functions.getName = function() {
  return this.name
}
Cat.functions.meow = function() {
  return `${this.getName()}eowww~~~~~, I"m ${this.age} year(s) old`
}

但這樣調(diào)用起來(lái),你就要寫(xiě) animal.functions.getName(),并不方便。不要怕,JavaScript 這門(mén)語(yǔ)言本身已經(jīng)幫你內(nèi)置了這樣的支持。它內(nèi)部所用來(lái)存儲(chǔ)公共函數(shù)的變量,就是你熟知的 prototype。當(dāng)你調(diào)用對(duì)象上的方法時(shí)(如 cat.getName()),它會(huì)自動(dòng)去 Cat.prototype 上去幫你找 getName 函數(shù),而你只需要寫(xiě) cat.getName() 即可。兼具了功能的實(shí)現(xiàn)和語(yǔ)法的優(yōu)雅。

最后寫(xiě)出來(lái)的代碼會(huì)是這樣:

function Animal(name) {
  this.name = name
}
Animal.prototype.getName = function() {
  return this.name
}

function Cat(name, age) {
  Animal.call(this, name)
  this.age = age || 1
}
Cat.prototype = Object.create(Animal.prototype, { constructor: Cat })
Cat.prototype.meow = function() {
  return `${this.getName()}eowww~~~~~, I"m ${this.age} year(s) old`
}

請(qǐng)注意,只有函數(shù)才有 prototype 屬性,它是用來(lái)做原型繼承的必需品。

優(yōu)雅的 API:ES6 class

然鵝,上面這個(gè)寫(xiě)法仍然并不優(yōu)雅。在何處呢?一個(gè)是 prototype 這種暴露語(yǔ)言實(shí)現(xiàn)機(jī)制的關(guān)鍵詞;一個(gè)是要命的是,這個(gè)函數(shù)內(nèi)部的 this,依靠的是作為使用者的你記得使用 new 操作符去調(diào)用它才能得到正確的初始化。但是這里沒(méi)有任何線(xiàn)索告訴你,應(yīng)該使用 new 去調(diào)用這個(gè)函數(shù),一旦你忘記了,也不會(huì)有任何編譯期和運(yùn)行期的錯(cuò)誤信息。這樣的語(yǔ)言特性,與其說(shuō)是一個(gè)「繼承方案」,不如說(shuō)是一個(gè) bug,一個(gè)不應(yīng)出現(xiàn)的設(shè)計(jì)失誤。

而這兩個(gè)問(wèn)題,在 ES6 提供的 class 關(guān)鍵詞下,已經(jīng)得到了非常妥善的解決,盡管它叫一個(gè) class,但本質(zhì)上其實(shí)是通過(guò) prototype 實(shí)現(xiàn)的:

class Animal {
  constructor(name) {
    this.name = name
  }

  getName() {
    return this.name
  }
}

class Cat extends Animal {
  constructor(name, age) {
    super(name)
    this.age = age || 1
  }

  meow() {
    return `${this.getName()}eowww~~~~~, I"m ${this.age} year(s) old`
  }
}

如果你沒(méi)有使用 new 操作符,編譯器和運(yùn)行時(shí)都會(huì)直接報(bào)錯(cuò)。為什么呢,我們將在[下一篇文章][]講解

extends 關(guān)鍵字,會(huì)使解釋器直接在底下完成基于原型的繼承功能

現(xiàn)在,我們已經(jīng)看到了一套比較完美的繼承 API,也看到其底下使用 prototype 存儲(chǔ)公共變量的地點(diǎn)和原理。接下來(lái),我們要解決另外一個(gè)問(wèn)題:prototype 有了,實(shí)例對(duì)象應(yīng)該如何訪問(wèn)到它呢?這就關(guān)系到 JavaScript 的向上查找機(jī)制了。

簡(jiǎn)明的向上查找機(jī)制:__proto__
function Animal(name) {
  this.name = name
}
Animal.prototype.say = function() {
  return this.name
}
const cat = new Animal("kitty")

console.log(cat) // Animal { name: "kitty" }
cat.hasOwnProperty("say") // false

看上面

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/98785.html

相關(guān)文章

  • 體驗(yàn)js美第八課-面向?qū)ο髣?chuàng)建和繼承終結(jié)篇

    摘要:概述到這里我們講說(shuō)面向?qū)ο蟮南盗胁糠值淖詈笠粋€(gè)課程,面向?qū)ο蟊仨氄莆諆蓚€(gè)東西一個(gè)是對(duì)象的創(chuàng)建一個(gè)是繼承。只需要記住一句話(huà),屬性放在構(gòu)造函數(shù)里面,方法放在原型上。 概述 到這里我們講說(shuō)js面向?qū)ο蟮南盗胁糠值淖詈笠粋€(gè)課程,面向?qū)ο蟊仨氄莆諆蓚€(gè)東西一個(gè)是對(duì)象的創(chuàng)建一個(gè)是繼承。這節(jié)課我們重點(diǎn)說(shuō)說(shuō)這兩個(gè)問(wèn)題最后我們說(shuō)下在ES6里面面向?qū)ο笤趺赐妗?1對(duì)象的創(chuàng)建 我們第一節(jié)課已經(jīng)就會(huì)用了,單體模...

    jzzlee 評(píng)論0 收藏0
  • 理解 JavaScript(四)

    摘要:其工作原理我已經(jīng)在第一篇做了大部分的闡述我尚未提及的是在創(chuàng)建新對(duì)象的時(shí)候,會(huì)賦予新對(duì)象一個(gè)屬性指向構(gòu)造器的屬性。 第四篇拖了很久了,真是有點(diǎn)不好意思。實(shí)話(huà)實(shí)說(shuō),拖延很久的原因主要是沒(méi)想好怎么寫(xiě),因?yàn)檫@一篇的主題比較有挑戰(zhàn)性:原型和基于原型的繼承——啊~我終于說(shuō)出口了,這下沒(méi)借口拖延了== 原型 我(個(gè)人)不喜歡的,就是講原型時(shí)上來(lái)就拿類(lèi)做比較的,所以我不會(huì)這樣講。不過(guò)我的確講過(guò)構(gòu)造器函...

    cuieney 評(píng)論0 收藏0
  • JavaScript 闖關(guān)記

    摘要:對(duì)象數(shù)組初始化表達(dá)式,闖關(guān)記之上文檔對(duì)象模型是針對(duì)和文檔的一個(gè)。闖關(guān)記之?dāng)?shù)組數(shù)組是值的有序集合。數(shù)組是動(dòng)態(tài)的,根闖關(guān)記之語(yǔ)法的語(yǔ)法大量借鑒了及其他類(lèi)語(yǔ)言如和的語(yǔ)法。 《JavaScript 闖關(guān)記》之 DOM(下) Element 類(lèi)型 除了 Document 類(lèi)型之外,Element 類(lèi)型就要算是 Web 編程中最常用的類(lèi)型了。Element 類(lèi)型用于表現(xiàn) XML 或 HTML 元素...

    mj 評(píng)論0 收藏0
  • 進(jìn)擊的 JavaScript(八) 繼承

    摘要:也就是說(shuō),并不知道,等是屬于哪個(gè)對(duì)象的哪個(gè)構(gòu)造函數(shù)或者類(lèi)。構(gòu)造函數(shù)模式與原型模式相結(jié)合的模式。給新建的對(duì)象,添加屬性,建立與構(gòu)造函數(shù)之間的聯(lián)系。另一種就是構(gòu)造函數(shù)繼承了。 前面講完原型鏈,現(xiàn)在來(lái)講繼承,加深理解下。 一、對(duì)象的相關(guān)知識(shí) 什么是對(duì)象? 就是一些無(wú)序的 key : value 集合, 這個(gè)value 可以是 基本值,函數(shù),對(duì)象。(注意 key 和 value 之間 是冒號(hào) ...

    ddongjian0000 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<