基本用法
class之間可以通過extends關鍵字實作繼承,寫法上比es5更加清晰
class Point{}
class FriendPoint extends Point{ //FriendPoint 繼承了Point類的所有屬性和方法
constructor(x,y,name){
super(x,y) //呼叫父類的constructor(x,y)
this.friend= color
}
toString(){
return this.friend+ '' + super.toString() //呼叫父類的的toString
}
}
在子類中出現了super關鍵字 表示父類的建構式,用來創建父類的this,子類沒有自己的this,必須在constructor中呼叫呼叫super方法,繼承父類的this,然后對其加工,否則會報錯,沒有this物件
class FriendPoint extends Point{
constructor(){
}
}
let friend = new FriendPoint() // Must call super constructor in derived class before accessing 'this' or returning from derived constructor
es5的繼承是先創建子類的this 再將父類的this添加到子類的this上面,es6是先創建父類的實體物件的this 先呼叫super方法,然后再用子類的建構式修改父類的this,要不不能使用this關鍵字,會報錯
類的prototype屬性和__proto__屬性
es5中每個物件都有一個__proto__屬性 指向對應的建構式的prototype屬性
class作為建構式的語法糖 也有prototype和__proto__屬性,同時存在著兩條繼承鏈
class A{}
class B extends A{
constructor(){
super()
}
}
let ob = new B()
console.log(B.__proto__) //class A
console.log(B.__proto__ === A) //true
console.log(B.prototype.__proto__ === A.prototype) //true
//子類B__proto__屬性指向父類A 子類B.prototype的屬性__proto__指向父類A的prototype屬性
// 就相當于
class A{}
class B{}
//B的原型繼承A的原型
Object.setPrototypeOf(B.prototype,A.prototype)
//B繼承A
Object.setPrototypeOf(B,A)
就是可以理解為
作為一個物件 子類B的原型 (__proto__屬性) 指向的是父類A,B.proto = A 比如說一個建構式的原型物件可能還有一個__proto__指向object
作為一個建構式 子類B的原型(prototype屬性)就是父類A的實體B.prototype.proto = A.prototype
繼承目標
只要父類(class B extend A{}) A只要是一個有prototype屬性的函式都能被B繼承 除了Function.prototype函式,Function.prototype.prototype是undefined,還有三種特殊情況
// 可以繼承Object類
class C extends Object{
}
console.log(C.__proto__ === Object) //true
console.log(C.prototype.__proto__ === Object.prototype) //true
//不做任何繼承
class C{
}
//C就相當與普通的建構式物件 相當于new Function() 所以
console.log( C.__proto__ === Function.prototype) //true
//普通的建構式物件的__proto__就是Object.prototype
//比如
function C(){
}
console.log(C.prototype.__proto__ == Object.prototype) //true
//第三種繼承null
class C extends null {
}
// C也是一個普通函式,所以直接繼承Funciton.prototype
C.__proto__ === Function.prototype // true
// 但是A.原型物件不繼承任何方法 相當于Object.setPrototypeOf(C.prototype,null)
C.prototype.__proto__ === undefined // true
//相當于
function C(){
}
Object.setPrototypeOf(C.prototype,null)
console.log(C.prototype.__proto__ === undefined) //true
super關鍵字
super可以作為函式呼叫 也可以作為物件使用 而且必須是顯式的作為函式或者是物件使用
class A{}
class B extends A{
constructor(){
super()
//console.log(super) //'super' keyword unexpected here 無法看出是作為函式還是物件使用
console.log(super.valueOf()) //回傳的是一個物件 說明 super是一個物件 所以不會報錯
}
}
new B()
作為函式呼叫 代表父類的建構式
class A {
constructor(){
console.log(new.target.name) //指向正在執行的函式 new B()的時候指向的B
}
}
class B extends A {
constructor() {
super(); //必須的,代表呼叫父類的建構式 否則會報錯 相當于A.prototype.constructor.call(this)
}
m(){
super() //'super' keyword unexpected here作為函式只能用在子類的建構式之中 否則會報錯
}
}
new B()
作為物件呼叫 指向的是父類的原型物件
class A {
constructor(){
this.a = 2
this.x = 3
}
m(){
return 1
}
point(){
return this.x
}
}
class B extends A{
constructor(){
super()
this.x = 4
console.log(super.m()) //1
console.log(super.a) //undefined 訪問不到實體屬性
//只能訪問到原型屬性 相當于 A.prototype
console.log(super.point()) //4
//通過super呼叫父類的方法的時候 super系結的是子類的this 實際上執行的是super.point.call(this),所以列印的是子類實體的this
super.x = 5
console.log(super.x) //undefined
console.log(this.x) //5
//由于super系結的是子類的this,所以相當于this.x =5 相當于給子類實體的x賦值
}
}
let b = new B()
實體的__proto__屬性
class A{}
class B extends A{
constructor(){
super()
}
}
let a = new A()
let b = new B()
// 因為 b.__proto__屬性是 B.prototype
// 所以
console.log(b.__proto__.__proto__ === A.prototype) //true
// 所以
console.log(b.__proto__.__proto__ === a.__proto__) //true
//所以通過子實體的__proto__.__proto__屬性 能修改父類實體的行為
b.__proto__.__proto__.getName = function(){
return 2
}
console.log(a.getName()) //2 會先在實體上找這個方法 找不到就去原型上找
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/274083.html
標籤:其他
上一篇:【JavaP6大綱】Dubbo篇:Dubbo 支持哪些序列化協議?說一下 Hessian 的資料結構?PB 知道嗎?為什么 PB 的效率是最高的?
