成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript 原型繼承之精髓

xingqiba / 2293人閱讀

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

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

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

目錄

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

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

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

簡明的向上查找機(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)類似于一個(gè)「對(duì)象」的概念)的封裝,才是繼承技術(shù)所必須出現(xiàn)的地方。為了滿足這樣的代碼復(fù)用,一個(gè)繼承體系的設(shè)計(jì)需要支持什么需求呢?

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

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

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

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

增加新成員的能力

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

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

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

JavaScript 的繼承有多種實(shí)現(xiàn)方式,具體有哪些,推薦讀者可閱讀:[JavaScript 語言精粹][]一書 和 這篇文章。這里,我們直接看一版比較優(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í)例。

怎么辦呢?想法也很簡單,就是把它們放到同一個(gè)地方去,并且還要跟這個(gè)「對(duì)象」關(guān)聯(lián)起來。如此一想,用來生成這個(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)用起來,你就要寫 animal.functions.getName(),并不方便。不要怕,JavaScript 這門語言本身已經(jīng)幫你內(nèi)置了這樣的支持。它內(nèi)部所用來存儲(chǔ)公共函數(shù)的變量,就是你熟知的 prototype。當(dāng)你調(diào)用對(duì)象上的方法時(shí)(如 cat.getName()),它會(huì)自動(dòng)去 Cat.prototype 上去幫你找 getName 函數(shù),而你只需要寫 cat.getName() 即可。兼具了功能的實(shí)現(xiàn)和語法的優(yōu)雅。

最后寫出來的代碼會(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 屬性,它是用來做原型繼承的必需品。

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

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

而這兩個(gè)問題,在 ES6 提供的 class 關(guān)鍵詞下,已經(jīng)得到了非常妥善的解決,盡管它叫一個(gè) class,但本質(zhì)上其實(shí)是通過 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`
  }
}

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

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

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

簡明的向上查找機(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://systransis.cn/yun/98785.html

相關(guān)文章

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

    摘要:概述到這里我們講說面向?qū)ο蟮南盗胁糠值淖詈笠粋€(gè)課程,面向?qū)ο蟊仨氄莆諆蓚€(gè)東西一個(gè)是對(duì)象的創(chuàng)建一個(gè)是繼承。只需要記住一句話,屬性放在構(gòu)造函數(shù)里面,方法放在原型上。 概述 到這里我們講說js面向?qū)ο蟮南盗胁糠值淖詈笠粋€(gè)課程,面向?qū)ο蟊仨氄莆諆蓚€(gè)東西一個(gè)是對(duì)象的創(chuàng)建一個(gè)是繼承。這節(jié)課我們重點(diǎn)說說這兩個(gè)問題最后我們說下在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í)話實(shí)說,拖延很久的原因主要是沒想好怎么寫,因?yàn)檫@一篇的主題比較有挑戰(zhàn)性:原型和基于原型的繼承——啊~我終于說出口了,這下沒借口拖延了== 原型 我(個(gè)人)不喜歡的,就是講原型時(shí)上來就拿類做比較的,所以我不會(huì)這樣講。不過我的確講過構(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)記之語法的語法大量借鑒了及其他類語言如和的語法。 《JavaScript 闖關(guān)記》之 DOM(下) Element 類型 除了 Document 類型之外,Element 類型就要算是 Web 編程中最常用的類型了。Element 類型用于表現(xiàn) XML 或 HTML 元素...

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

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

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

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

0條評(píng)論

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