日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

手把手教你如何实现继承

發(fā)布時(shí)間:2023/12/9 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 手把手教你如何实现继承 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文將從最簡(jiǎn)單的例子開始,從零講解在 JavaScript 中如何實(shí)現(xiàn)繼承。


小例子

現(xiàn)在有個(gè)需求,需要實(shí)現(xiàn) Cat 繼承 Animal ,構(gòu)造函數(shù)如下:

function Animal(name){this.name = name }function Cat(name){this.name = name } 復(fù)制代碼

注:如對(duì)繼承相關(guān)的 prototype、constructor、__proto__、new 等內(nèi)容不太熟悉,可以先查看這篇文章:理性分析 JavaScript 中的原型


繼承

在實(shí)現(xiàn)這個(gè)需求之前,我們先談?wù)劺^承的意義。繼承本質(zhì)上為了提高代碼的復(fù)用性。

對(duì)于 JavaScript 來說,繼承有兩個(gè)要點(diǎn):

  • 復(fù)用父構(gòu)造函數(shù)中的代碼
  • 復(fù)用父原型中的代碼
  • 下面的內(nèi)容將圍繞這兩個(gè)要點(diǎn)展開。

    第一版代碼

    復(fù)用父構(gòu)造函數(shù)中的代碼,我們可以考慮調(diào)用父構(gòu)造函數(shù)并將 this 綁定到子構(gòu)造函數(shù)。

    復(fù)用父原型中的代碼,我們只需改變?cè)玩溂纯?。將子?gòu)造函數(shù)的原型對(duì)象的 __proto__ 屬性指向父構(gòu)造函數(shù)的原型對(duì)象。

    第一版代碼如下:

    function Animal(name){this.name = name }function Cat(name){Animal.call(this,name) }Cat.prototype.__proto__ = Animal.prototype 復(fù)制代碼

    檢驗(yàn)一下是否繼承成功:我們?cè)?Animal 的原型對(duì)象上添加 eat 函數(shù)。使用 Cat 構(gòu)造函數(shù)生成一個(gè)名為 'Tom' 的實(shí)例對(duì)象 cat 。代碼如下:

    function Animal(name){this.name = name }function Cat(name){Animal.call(this,name) }Cat.prototype.__proto__ = Animal.prototype// 添加 eat 函數(shù) Animal.prototype.eat = function(){console.log('eat') }var cat = new Cat('Tom') // 查看 name 屬性是否成功掛載到 cat 對(duì)象上 console.log(cat.name) // Tom // 查看是否能訪問到 eat 函數(shù) cat.eat() // eat // 查看 Animal.prototype 是否位于原型鏈上 console.log(cat instanceof Animal) // true // 查看 Cat.prototype 是否位于原型鏈上 console.log(cat instanceof Cat) //true 復(fù)制代碼

    經(jīng)檢驗(yàn),成功復(fù)用父構(gòu)造函數(shù)中的代碼,并復(fù)用父原型對(duì)象中的代碼,原型鏈正常。

    圖示

    弊端

    __proto__ 屬性雖然可以很方便地改變?cè)玩?#xff0c;但是 __proto__ 直到 ES6 才添加到規(guī)范中,存在兼容性問題,并且直接使用 __proto__ 來改變?cè)玩湻浅O男阅?。所?__proto__ 屬性來實(shí)現(xiàn)繼承并不可取。

    第二版代碼

    針對(duì) __proto__ 屬性的弊端,我們考慮使用 new 操作符來替代直接使用 __proto__ 屬性來改變?cè)玩湣?/p>

    我們知道實(shí)例對(duì)象中的 __proto__ 屬性指向構(gòu)造函數(shù)的 prototype 屬性的。這樣我們 Animal 的實(shí)例對(duì)象賦值給 Cat.prototype 。不就也實(shí)現(xiàn)了Cat.prototype.__proto__ = Animal.prototype 語句的功能了嗎?

    代碼如下:

    function Animal(name){this.name = name }function Cat(name){Animal.call(this,name) }Cat.prototype = new Animal() Cat.prototype.constructor = Cat 復(fù)制代碼

    使用這套方案有個(gè)問題,就是在將實(shí)例對(duì)象賦值給 Cat.prototype 的時(shí)候,將 Cat.prototype 原有的 constructor 屬性覆蓋了。實(shí)例對(duì)象的 constructor 屬性向上查詢得到的是構(gòu)造函數(shù) Animal 。所以我們需要矯正一下 Cat.prototype 的 constructor 屬性,將其設(shè)置為構(gòu)造函數(shù) Cat 。

    圖示

    優(yōu)點(diǎn)

    兼容性比較好,并且實(shí)現(xiàn)較為簡(jiǎn)單。

    弊端

    使用 new 操作符帶來的弊端是,執(zhí)行 new 操作符的時(shí)候,會(huì)執(zhí)行一次構(gòu)造函數(shù)將構(gòu)造函數(shù)中的屬性綁定到這個(gè)實(shí)例對(duì)象。這樣就多執(zhí)行了一次構(gòu)造函數(shù),將原本屬于 Animal 實(shí)例對(duì)象的屬性混到 prototype 中了。

    第三版代碼

    考慮到第二版的弊端,我們使用一個(gè)空構(gòu)造函數(shù)來作為中介函數(shù),這樣就不會(huì)將構(gòu)造函數(shù)中的屬性混到 prototype 中,并且減少了多執(zhí)行一次構(gòu)造函數(shù)帶來的性能損耗。

    代碼如下:

    function Animal(name){this.name = name }function Cat(name){Animal.call(this,name) } function Func(){} Func.prototype = Animal.prototypeCat.prototype = new Func() Cat.prototype.constructor = Cat 復(fù)制代碼

    圖示

    ES6

    使用 ES6 就方便多了。可以使用 extends 關(guān)鍵字實(shí)現(xiàn)繼承, 復(fù)用父原型中的代碼。使用 super 關(guān)鍵字來復(fù)用父構(gòu)造函數(shù)中的代碼。

    代碼如下:

    class Animal {constructor(name){this.name = name}eat(){console.log('eat')} } class Cat extends Animal{constructor(name){super(name)} }let cat = new Cat('Tom') console.log(cat.name) // Tom cat.eat() // eat 復(fù)制代碼

    相關(guān)知識(shí)點(diǎn)

    • 理性分析 JavaScript 中的 this
    • 理性分析 JavaScript 中的原型

    參考書籍

    • 《JavaScript高級(jí)程序設(shè)計(jì)(第3版)》
    • 《Java核心技術(shù) 卷Ⅰ(第9版)》

    總結(jié)

    以上是生活随笔為你收集整理的手把手教你如何实现继承的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。