目錄
ES6 Class 的繼承
為什麼子類別的建構函數,一定要呼叫super()?
首頁 web前端 前端問答 es6中用什麼實作繼承

es6中用什麼實作繼承

Feb 14, 2023 pm 01:56 PM
es6 前端 繼承

es6中用class和extends關鍵字來實現繼承。 ES6中引入了class關鍵字來聲明類,而class(類)可透過extends關鍵字實現繼承,讓子類繼承父類的屬性和方法,語法「class 父類名{...} class 子類名extends 父類別名稱{...};」。

es6中用什麼實作繼承

本教學操作環境:windows7系統、ECMAScript 6版、Dell G3電腦。

es6中可利用class關鍵字配合extends關鍵字來實現繼承。

ES6 Class 的繼承

#1.簡介

Class可以透過extends關鍵字實作繼承,讓子類別繼承父類別的屬性和方法。這比 ES5 的透過修改原型鏈實現繼承,要清晰和方便很多。

//父类
class Point {
 ...
}
//子类
class ColorPoint extends Point {
	constructor(x, y, color) {
		super(x, y);
		this.color = color;
	}
	toString() {
		return this.color + '' + super.toString(); // 调用父类的toString方法
	}
}
登入後複製

上面程式碼中,constructor方法和toString方法內部,都出現了super關鍵字,super在這裡表示父類別的建構函數,用來新建一個父類別的實例物件。

ES6規定,子類別必須在constructor方法中呼叫super(),否則會報錯,這是因為子類別自己的this對象,必須先透過父類別的建構子完成塑造,得到與父類同樣的實例屬性和方法,然後在加入子類別自己的實例屬性和方法。

為什麼子類別的建構函數,一定要呼叫super()?

這是因為在ES5的繼承機制中,是先創造一個獨立的子類別的實例對象,然後再將父類別的方法加入到這個物件上,也就是「實例在前,繼承在後」;ES6的繼承機制,則是先將父類別的屬性和方法,加到一個空的物件上面,然後再將該物件作為子類別的實例,即“繼承在前,實例在後” 。

這意味著,每次新建子類別實例時,父類別的建構子必定會先執行一次

class Foo {
	constructor() {
		console.log(1);
	}
}

class Bar extends Foo {
	constructor() {
		super();
		console.log(2);
	}
}

const bar = new Bar(); // 1 2
登入後複製

上面的程式碼中,子類別Bar新建實例時,就會輸出1和2,這就是因子類別建構子呼叫super()時,會執行一次父類別建構子。只有在子類別的建構子中呼叫super之後,才可以使用this關鍵字,否則會報錯。這是因為子類別實例的構建,必須先完成父類別的繼承,只有super方法才能讓子類別實例繼承父類別。

class Point {
	constructor(x, y) {
		this.x = x;
		this.y = y;
	}
}

class ColorPoint extends Point {
	constructor(x, y, color) {
		this.color = color;
		super(x, y);
		this.color = color;
	}
}"
登入後複製

如果子類別沒有定義constructor方法,這個方法會預設添加,並且裡面會呼叫super,也就是說,不管有沒有顯示定義,任何一個子類別都有constructor方法.

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}
class ColorPoint extends Point {
}

let cp = new ColorPoint(25, 8);
console.log(cp); //{x: 25, y: 8}

class ColorPoint extends Point {
  constructor(...args) {
    super(...args);
  }
}

let cp = new ColorPoint(25, 8);
console.log(cp); //{x: 25, y: 8}
登入後複製

2.私有屬性和私有方法的繼承

父類別所有的屬性和方法,都會被子類別繼承,除了私有的屬性和方法。子類別無法繼承父類別的私有屬性,或者說私有屬性只能在定義它的class裡面使用。

class Foo {
  #p = 1;
  #m() {
    console.log('hello');
  }
}

class Bar extends Foo {
  constructor() {
    super();
    console.log(this.#p); // 报错
    this.#m(); // 报错
  }
}
登入後複製

上面範例中,子類別 Bar 呼叫父類別 Foo 的私有屬性或私有方法,都會報錯。

如果父類別定義了私有屬性的讀寫方法,子類別就可以透過這些方法,讀寫私有屬性。

class Foo {
  #p = 1;
  getP() {
    return this.#p;
  }
}

class Bar extends Foo {
  constructor() {
    super();
    console.log(this.getP()); // 1
  }
}
登入後複製

3.靜態屬性和方法的繼承

#父類別的靜態屬性和靜態方法,也會被子類別繼承。

class A {
  static hello() {
    console.log('hello world');
  }
}

class B extends A {
}

B.hello()  // hello world
登入後複製

上面程式碼中,hello()A類別的靜態方法,B繼承A,也繼承了A的靜態方法。

注意,靜態屬性是透過淺拷貝實作繼承的,如果繼承的屬性是原始資料類型,子類別中操作繼承的靜態屬性不會影響到父類,但如果繼承的屬性是物件,那麼子類別修改這個屬性會印像到父類別

class C {
	static foo = 100;
}

class D extends C {
	constructor() {
		super();
		D.foo--;
	}
}

const d = new D();
C.foo; // 100
D.foo;  // 99

class A {
	static foo = { n: 100 };
}

class B extends A {
	constructor() {
		super();
		B.foo.n--;
	}
}

const b = new B();
B.foo.n // 99
A.foo.n  // 99
登入後複製

4.Object.getPrototypeOf()

Object.getPrototypeOf ()方法可以用來從子類別上取得父類別。

class Point { /*...*/ }

class ColorPoint extends Point { /*...*/ }

Object.getPrototypeOf(ColorPoint) === Point
// true
登入後複製

因此,可以使用這個方法來判斷,一個類別是否繼承了另一個類別。

5.super關鍵字

#super關鍵字既可以當做函數使用,也可以當做物件使用

第一種情況,super當函數呼叫時,代表父類別的建構子。呼叫super的作用是形成子類別的this對象,把父類別的實例屬性和方法都放到這個this物件上面。

class A {
	constructor() {
    console.log(new.target.name);
  }
}

class B extends A {
	constructor() {
		super();
	}
}

new A(); // A
new B(); // B
登入後複製

第二種情況,super作為物件時,在普通方法中,指向父類別的原型物件;在靜態方法中,指向父類別。

class A {
	p() {
    return 2;
  }
}

class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2
  }
}

let b = new B();
登入後複製

上面程式碼中,子類別B中的super.p(),將super當做一個物件使用,這時super在普通物件中,指向的是A.prototype,super.p()相當於A.prototype.p()。

由於super指向父類別的原型對象,所以定義在父類別實例上的方法或屬性,是無法透過super呼叫的。如下所示:

class A {
	constructor() {
		this.p = 2;
	}
}

class B extends A {
	get m() {
		return spuer.p;
	}
}

let b = new B();
b.m // undefined
登入後複製

為了解決這種問題,可以將屬性定義在父類別的原型物件上

class A {};
A.prototype.x = 2;

class B extends A {
	constructor() {
		super();
		console.log(super.x);
	}
}

let b = new B();
登入後複製

ES6規定,在子類別普通方法中透過super呼叫父類別的方法時,方法內部的this指向目前的子類別實例

class A {
	constructor() {
		this.x = 1;
	}
	print() {
		console.log(this.x);
	}
}

class B extends A {
	constructor() {
		super();
		this.x = 2;
	}
	m() {
		super.print();
	}
}

let b = new B();
b.m(); // 2
登入後複製

上面代码中,super.print()调用的是A.prototype.print(),但是此时方法内部的this指向是子类B的实例,所以输出2。

由于this指向的是子类实例,所有如果通过super对某个属性赋值,这时super就是this,赋值的属性会变成子类实例的属性

class A {
	constructor() {
		this.x = 1;
	}
}

class B extends A {
	constructor() {
		super();
		this.x = 2;
		super.x = 3;
		console.log(super.x); //undefind
		console.log(this.x); // 3
	}
}
登入後複製

上面代码中,super.x赋值为3,这时等同于对this.x赋值为3。而当读取super.x 的时候,读的是A.prototype.x,所以返回undefined

如果super作为对象,用在静态方法之中,这时super将指向父类,而不是父类的原型对象。

class Parent {
	static myMethod(msg) {
		console.log('static', msg);
	}

	myMethod(msg) {
		console.log('instance', msg);
	}
}

class Children extends Parent {
	static myMethod(msg) {
		super.myMthod(msg);
	}

	myMethod(msg) {
    super.myMethod(msg);
  }
}

Child.myMethod(1); // static 1

var child = new Child();
child.myMethod(2); // instance 2
登入後複製

上面代码中,super在静态方法之中指向父类,在普通方法之中指向父类的原型对象。

另外,在子类的静态方法中通过super调用父类的方法时,方法内部的this指向当前的子类,而不是子类的实例

class A {
	constructor() {
    this.x = 1;
  }
  static print() {
    console.log(this.x);
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
  }
  static m() {
    super.print();
  }
}

B.x = 3;
B.m() // 3
登入後複製

在静态方法m中,super.print指向父类的静态方法,到那时this指向的是类B,而不是B的实例。

【推荐学习:javascript高级教程

以上是es6中用什麼實作繼承的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前 By 尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

C++ 函式繼承詳解:如何在繼承中使用「基底類別指標」和「衍生類別指標」? C++ 函式繼承詳解:如何在繼承中使用「基底類別指標」和「衍生類別指標」? May 01, 2024 pm 10:27 PM

C++ 函式繼承詳解:如何在繼承中使用「基底類別指標」和「衍生類別指標」?

PHP與Vue:完美搭檔的前端開發利器 PHP與Vue:完美搭檔的前端開發利器 Mar 16, 2024 pm 12:09 PM

PHP與Vue:完美搭檔的前端開發利器

前端面試官常問的問題 前端面試官常問的問題 Mar 19, 2024 pm 02:24 PM

前端面試官常問的問題

C++ 中繼承和多態性如何影響類別的耦合度? C++ 中繼承和多態性如何影響類別的耦合度? Jun 05, 2024 pm 02:33 PM

C++ 中繼承和多態性如何影響類別的耦合度?

C++ 函式繼承詳解:如何偵錯繼承中出現的錯誤? C++ 函式繼承詳解:如何偵錯繼承中出現的錯誤? May 02, 2024 am 09:54 AM

C++ 函式繼承詳解:如何偵錯繼承中出現的錯誤?

什麼是前端模組化ESM? 什麼是前端模組化ESM? Feb 25, 2024 am 11:48 AM

什麼是前端模組化ESM?

Go語言前端技術探秘:前端開發新視野 Go語言前端技術探秘:前端開發新視野 Mar 28, 2024 pm 01:06 PM

Go語言前端技術探秘:前端開發新視野

C++ 函式繼承詳解:什麼時候不該使用繼承? C++ 函式繼承詳解:什麼時候不該使用繼承? May 04, 2024 pm 12:18 PM

C++ 函式繼承詳解:什麼時候不該使用繼承?

See all articles