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这个实例化对象