es6的新特性裡增加了類和類的繼承,其實這個特性也是向背景語言借鑒過來的,先來看下es5的時候如何構造一個對象
function Human(){
this.eyes=2;
this.hands=2;
}
Human.prototype.singing=function(){
console.log('I can sing');
}
let a = new Human();
console.log(a);
a.singing();
如上,用es5的方法構造了一個叫Human的對象,在對象裡建立了2個屬性,并用prototype的方法挂載了一個方法,申明了一個a為Human對象的執行個體化,并用這個a調用singing這個方法
再來看,如何用es6來申明一個類:
class Human{
constructor(){
this.eyes=2;
this.hands=2;
}
}
let a = new Human();
console.log(a);
es6用class關鍵字來申明一個類,并用constructor來建立一個類的構造函數,初始化一個對象的屬性,其實es6隻是用了一種更語義化、更規範的方式去申明一個類,但是其背後的原理還是基于es5的,如果要建立一個方法,也無需再挂載到原型上 直接在對象裡建立
class Human{
constructor(){
this.eyes=2;
this.hands=2;
}
singing(){
console.log('I can sing');
}
}
let a = new Human();
console.log(a);
a.singing();
es6裡是如何繼承類的呢
class Human{
constructor(){
this.eyes=2;
this.hands=2;
}
singing(){
console.log('I can sing');
}
}
let a = new Human();
console.log(a);
a.singing();
class NormalMan extends Human {
}
let b=new NormalMan();
console.log(b);
類可以繼承另外一個類,使用extends文法,可以繼承到另外一個類的所有屬性和方法,除此之外,它也可以改造繼承過來的屬性和方法或者建立新的屬性和方法
class Human{
constructor(){
this.eyes=2;
this.hands=2;
}
singing(){
console.log('I can sing');
}
}
let a = new Human();
console.log(a);
a.singing();
class NormalMan extends Human {
constructor(){
super();
this.eyes=100;
this.hands=200;
this.feet=2;
}
singing(){
console.log('NormalMan can sing');
}
run(){
console.log('NormalMan can run');
}
}
let b=new NormalMan();
console.log(b);
b.singing();
b.run();
可以在constructor裡改造繼承過來的屬性,還可以建立自己的方法,super()調用了一下父類的構造函數,當繼承了另外一個類的時候就必須使用,如果不用就會報錯。
我們可以在父類的構造函數裡傳參,在調用的時候傳參
class Human{
constructor(eyes=2,hands=2){
this.eyes=eyes;
this.hands=hands;
}
singing(){
console.log('I can sing');
}
}
let a = new Human(3,4);
console.log(a);
a.singing();
class NormalMan extends Human {
constructor(){
super();
this.eyes=100;
this.hands=200;
this.feet=2;
}
singing(){
console.log('NormalMan can sing');
}
run(){
console.log('NormalMan can run');
}
}
let b=new NormalMan();
console.log(b);
b.singing();
b.run();
super()裡調用的是父類的構造函數,是以super()裡也可以傳參
class Human{
constructor(eyes=2,hands=2){
this.eyes=eyes;
this.hands=hands;
}
singing(){
console.log('I can sing');
}
}
let a = new Human(3,4);
console.log(a);
a.singing();
class NormalMan extends Human {
constructor(){
super(1000,2000);
this.feet=2;
}
singing(){
console.log('NormalMan can sing');
}
run(){
console.log('NormalMan can run');
}
}
let b=new NormalMan();
console.log(b);
b.singing();
b.run();
關于構造函數裡的this指向,我們可以在繼承的函數的構造函數裡面傳一個name的參數,并在構造函數裡建立一個name的屬性,在singing()的方法裡可以用模闆字元串${this.name}去拼接,最後在執行個體化的NormalMan()裡傳入Mike,最後列印出來NormalMan這個對象裡有name: "Mike"
如果用另外一個變量去接收b裡面singing的方法 ,再調用這個方法,這個時候就和運作一個普通函數一樣,這時再去列印this,this就為undefined
class Human{
constructor(eyes=2,hands=2){
this.eyes=eyes;
this.hands=hands;
}
singing(){
console.log('I can sing');
}
}
let a = new Human(3,4);
console.log(a);
a.singing();
class NormalMan extends Human {
constructor(name='Flowke'){
super(1000,2000);
this.feet=2;
this.name=name;
}
singing(){
console.log(this);
/*console.log(`${this.name} can sing`);*/
}
run(){
console.log('NormalMan can run');
}
}
let b=new NormalMan('Mike');
console.log(b);
b.singing();
b.run();
let fnn=b.singing;
fnn();
那該怎麼去解決這個問題呢,如何讓這個this永遠指向new出來的這個執行個體?可以在constructor的構造函數裡寫上這句 this.singing=this.singing.bind(this);
class Human{
constructor(eyes=2,hands=2){
this.eyes=eyes;
this.hands=hands;
}
singing(){
console.log('I can sing');
}
}
let a = new Human(3,4);
console.log(a);
a.singing();
class NormalMan extends Human {
constructor(name='Flowke'){
super(1000,2000);
this.feet=2;
this.name=name;
this.singing=this.singing.bind(this);
}
singing(){
/*console.log(this);*/
console.log(`${this.name} can sing`);
}
run(){
console.log('NormalMan can run');
}
}
let b=new NormalMan('Mike');
console.log(b);
b.singing();
b.run();
let fnn=b.singing;
fnn();
this.singing=this.singing.bind(this);後面的this.singing就是指後面的singing()這個方法,後面綁定了this,那這個時候let fnn=b.singing,這裡的b.singing通路的就是this.singing,而這裡this.singing已經綁定了this的指向,這個時候去運作fnn,而這個this就是指構造的時候類的執行個體,這個時候運作fnn,就會發現列印出來的是mike也就是b這個執行個體化對象