欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS高級(jí)程序設(shè)計(jì)之class繼承重點(diǎn)詳解

 更新時(shí)間:2022年07月06日 15:16:23   作者:掘金安東尼  
這篇文章主要為大家介紹了JS高級(jí)程序設(shè)計(jì)之class繼承重點(diǎn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

前文已提過(guò):在 class 出現(xiàn)之前,JavaScript 實(shí)現(xiàn)繼承是件麻煩事,構(gòu)造函數(shù)繼承有加上原型上的函數(shù)不能復(fù)用的問(wèn)題;原型鏈繼承又存在引用值屬性的修改不獨(dú)立的問(wèn)題;組合繼承又存在兩次調(diào)用構(gòu)造函數(shù)的問(wèn)題,寄生組合繼承,寫(xiě)起來(lái)又太麻煩了,總之,在 class 出現(xiàn)前,JavaScipt 實(shí)現(xiàn)繼承真是件麻煩事兒。

然而,class 的出現(xiàn)真的改變這一現(xiàn)狀了嗎?

不如往下看。

寫(xiě)法

與函數(shù)類(lèi)型相似,定義類(lèi)也有兩種主要方式:類(lèi)聲明和類(lèi)表達(dá)式。

// 類(lèi)聲明 class Person {}

// 類(lèi)表達(dá)式 const Animal = class {};

不過(guò),與函數(shù)定義不同的是,雖然函數(shù)聲明可以提升,但類(lèi)定義不能。

與函數(shù)構(gòu)造函數(shù)一樣,多數(shù)編程風(fēng)格都建議類(lèi)名的首字母要大寫(xiě),以區(qū)別于通過(guò)它創(chuàng)建的實(shí)例。

類(lèi)可以包含:

  • 構(gòu)造函數(shù)方法
  • 實(shí)例方法
  • 獲取函數(shù)
  • 設(shè)置函數(shù)
  • 靜態(tài)類(lèi)方法

這些項(xiàng)都是可選的

constructor

class Person { 
    constructor(name) {
        this.name = name
        console.log('person ctor');
    }
}
let p1 = new Person("p1")

constructor 會(huì)告訴解釋器 在使用 new 操作符創(chuàng)建類(lèi)的新實(shí)例時(shí),應(yīng)該調(diào)用這個(gè)函數(shù)。

等同于

function Person(name){
    this.name = name
    console.log('person ctor')
}
let p1 = new Person("p1")

類(lèi)構(gòu)造函數(shù)與構(gòu)造函數(shù)的主要區(qū)別是,這樣寫(xiě)會(huì)報(bào)錯(cuò):

class Animal {}
let a = Animal(); // TypeError: class constructor Animal cannot be invoked without 'new'

所以,new 操作符是強(qiáng)制要寫(xiě)的;

使用 new 時(shí),原理與 new 一個(gè)對(duì)象也是一樣的,因?yàn)樘匾?,再?gòu)?qiáng)調(diào)一遍:

(1) 在內(nèi)存中創(chuàng)建一個(gè)新對(duì)象。

(2) 這個(gè)新對(duì)象內(nèi)部的[[Prototype]]指針被賦值為構(gòu)造函數(shù)的 prototype 屬性。

(3) 構(gòu)造函數(shù)內(nèi)部的 this 被賦值為這個(gè)新對(duì)象(即 this 指向新對(duì)象)。

(4) 執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼(給新對(duì)象添加屬性)。

(5) 如果構(gòu)造函數(shù)返回非空對(duì)象,則返回該對(duì)象;否則,返回剛創(chuàng)建的新對(duì)象。

特性

從各方面來(lái)看,ECMAScript 類(lèi)就是一種特殊函數(shù)。

我們可以用 typeof 打印試試:

class Person {} 
console.log(typeof Person); // function

也可以用 instanceof 檢查它的原型鏈

class Person {} 
let p = new Person()
console.log(p instanceof Person); // true

通過(guò) class 構(gòu)造的每個(gè)實(shí)例都對(duì)應(yīng)一個(gè)唯一的成員對(duì)象,這意味著所有成員都不會(huì)在原型上共享;

class Person {
 constructor() {
 this.name = new String('Jack');
 this.sayName = () => console.log(this.name);
 }
}
let p1 = new Person();
let p2 = new Person();
console.log(p1.name === p2.name) // false
console.log(p1.sayName === p2.sayName) // false

如果想要共享,就改寫(xiě)成方法,寫(xiě)在 constructor 外面:

class Person {
 constructor() {
 this.name = new String('Jack');
 }
 sayName(){
      console.log(this.name);
 }
}
let p1 = new Person();
let p2 = new Person();
console.log(p1.sayName === p2.sayName) // true

我們可以在方法前面加 static 關(guān)鍵字,實(shí)現(xiàn):靜態(tài)類(lèi)成員。我們不能在類(lèi)的實(shí)例上調(diào)用靜態(tài)方法,只能通過(guò)類(lèi)本身調(diào)用。不做贅述。

繼承

ECMAScript 6 新增特性中最出色的一個(gè)就是原生支持了類(lèi)繼承機(jī)制。雖然類(lèi)繼承使用的是新語(yǔ)法,但背后依舊使用的是原型鏈。

讓我們?cè)倩仡櫂?gòu)造函數(shù)繼承和原型鏈繼承 2 個(gè)經(jīng)典的問(wèn)題:

① 構(gòu)造函數(shù)繼承的問(wèn)題:構(gòu)造函數(shù)外在原型上定義方法,不能重用

function SuperType(){}
SuperType.prototype.sayName = ()=>{console.log("bob")}
function SubType(){
    SuperType.call(this) // 構(gòu)造函數(shù)繼承
}
let p1 = new SubType()
console.log(p1.sayName()) // Uncaught TypeError: p1.sayName is not a function

而原型鏈繼承可以解決這一點(diǎn):

function SuperType(){}
SuperType.prototype.sayName = ()=>{console.log("bob")}
function SubType(){}
SubType.prototype = new SuperType()  // 原型鏈繼承
let p1 = new SubType()
console.log(p1.sayName()) // bob

② 原型鏈繼承的問(wèn)題:原型中包含的引用值會(huì)在所有實(shí)例間共享。

function SuperType(){
    this.name = ["bob","tom"];
}
function SubType(){}
SubType.prototype = new SuperType()  // 原型鏈繼承
let p1 = new SubType()
p1.name.push("jerry")
let p2 = new SubType()
console.log(p2.name) //  ['bob', 'tom', 'jerry']

而構(gòu)造函數(shù)繼承可以解決這一點(diǎn):

function SuperType(){
    this.name = ["bob","tom"];
}
function SubType(){
    SuperType.call(this) // 構(gòu)造函數(shù)繼承
}
let p1 = new SubType()
p1.name.push("jerry")
let p2 = new SubType()
console.log(p2.name) //  ['bob', 'tom']

class 繼承有這兩個(gè)問(wèn)題嗎??

代碼一試便知:

class SuperType{}
SuperType.prototype.sayName = ()=>{console.log("bob")}
class SubType extends SuperType{
}
let p1 = new SubType()
p1.sayName() // bob

問(wèn)題①,沒(méi)有問(wèn)題,在構(gòu)造函數(shù)外寫(xiě)的原型繼承,公共方法還是能訪(fǎng)問(wèn)的?。?/p>

class SuperType{
    constructor(){
        this.name=["bob","tom"]
    }
}
class SubType extends SuperType{
}
let p1 = new SubType()
let p2 = new SubType()
p1.name.push("Jerry")
console.log(p2.name) //  ['bob', 'tom']

問(wèn)題②,沒(méi)有問(wèn)題,在 constructor 的引用值屬性,修改不會(huì)產(chǎn)生干涉?。?/p>

class 繼承完美的解決了構(gòu)造函數(shù)繼承的問(wèn)題,和原型鏈繼承的問(wèn)題,寫(xiě)起來(lái)也沒(méi)有組合繼承、寄生繼承那么麻煩,如果非得用 JS 模擬面向?qū)ο缶幊?,class 必不可少?。?/p>

題外話(huà)

其實(shí)寫(xiě) Class C 和 C.prototype 一起寫(xiě)是很危險(xiǎn)的:明明都在操作面向?qū)ο蟮念?lèi)了,還要操作原型鏈。類(lèi)操作和原型操作是兩種不同的設(shè)計(jì)思路,有興趣可見(jiàn)本瓜一年前的一篇文章:“類(lèi)”設(shè)計(jì)模式和“原型”設(shè)計(jì)模式——“復(fù)制”和“委托”的差異

以上就是JS高級(jí)程序設(shè)計(jì)之class繼承重點(diǎn)詳解的詳細(xì)內(nèi)容,更多關(guān)于JS高級(jí)程序設(shè)計(jì)class繼承的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論