在ES5及以前版本,是没有真正意义上类的概念,只是通过构造函数来模拟类的运用。尽管JS脚本语言是一门解释型弱语言,对类的需求意义不大,但ES6还是引入类的实现,让JS真正够上面向对象编程门槛,尽管对类的功能实现还不全面、彻底,但基本面向对象编程功能具有了。

一、ES5中的近类结构

由构造函数实现的近类能够对功能代码进行抽象定义与封装,实现代码重复运用与安全性,具有部分类的作用。但还不能算真正意义的类,因为它只有实例化运用功能,不具有类的直接继承与派生(只能通过间接方法),不能够对方法进行重写与多态、重载等表现。

function PersonType(name){//定义构造函数

       this.name=name;

}

PersonType.prototype.sayName=function(){//通过原型方法,给构造“类”添加方法

       console.log(this.name);

}

var person=new PersonType("张小玉");//实例化一个构造“类”

person.sayName(); //输出结果:张小玉

console.log(person instanceof PersonType);//输出结果:true

console.log(person instanceof Object);//输出结果:true

二、ES6中实现真正的类结构

(一)类的声明

class PersonClass{//或者写成:let PersonClass=class{

       //等价于构造函数

       constructor(name){

              this.name=name;

       }

       //等价于PersonType.prototype.sayName

       sayName(){

              console.log(this.name);

       }

}

let person=new PersonClass("张小玉");

person.sayName();//输出结果:张小玉

console.log(person instanceof PersonClass);//输出结果:true

console.log(person instanceof Object);//输出结果:true

console.log(typeof PersonClass);//输出结果:function

console.log(typeof PersonClass.prototype.sayName);//输出结果:function

从上可以看出,JS类的结构从本质上看还是函数,说明ES6的JS类还是对以前构造函数的包装,只是被打上了真正类的一些行为标签。

(二)为何要在ES6中引入类语法

1.以前的函数(包括构造函数)是要在作用域中被提升,而ES6的类不会被提升,它会处于临时死区中,也let定义一样,可以克服各种冲突与安全性问题。

2.类声明中所有代码将自动运行在严格模式下,而且无法强化让代码脱离严格模式。

3.构造函数的方法不可枚举,而类方法可以枚举。

4.在类中,如果调用没有通过[[construct]]定义过的方法会报错,而构造函数会默认采用新增方法,不会产生调用错误,这可能会造成较多误解。

三、ES6中类的功能实现

(一)静态成员实现

1.构造函数的静态成员实现

function PersonType(name){//定义构造函数

       this.name=name;

}

//静态方法

PersonType.crate=function(name){

       return name;

}

//实例方法

PersonType.prototype.sayName=function(){

       console.log(this.name);

}

var person=PersonType.crate("张小玉");//静态方法必须直接访问,不能在实例对象中访问

console.log(person);//输出结果:张小玉

2.ES6中类的静态成员实现

class PersonClass{

//等价于构造函数

       constructor(name){

              this.name=name;

       }

//等价于PersonType.prototype.sayName

       sayName(){

              console.log(this.name);

}

       //等价于PersonType.create

       static creat(name){

              return name;

       }

}

let person=PersonClass.creat("张小玉");//静态方法必须直接访问,不能在实例对象中访问

console.log(person); //输出结果:张小玉

(二)继承与派生

1.定义

class Rectangle{//定义父类

constructor(length,width){

       this.length=length;

       this.width=width;

}

getArea(){

        return this.length*this.width;

}

}

class Square extends Rectangle{//定义子类

       constructor(length){//继承派生方法

              super(length,length);//通过super方法访问父类构造方法

       }

}

var square=new Square(3);

console.log(square.getArea());//输出结果:9

console.log(square instanceof Square);//输出结果:true

2.使用super()方法的注意事项

(1)只可在派生类的构造函数中使用super(),如果尝试在非extends声明的类使用会抛出错误,反之如果在继承派生类中不使用super()方法继承父类,则系统会自动派生super(…args),将父类构造方法继承过来。

(2)在构造函数中访问this之前一定要调用super(),它负责初始化this,否则将出错。

(3)如果不想调super(),唯一的方法是让类的构造函数返回一个对象。

(三)类方法的遮蔽与重写

继承子类会自动遮蔽父类方法,需要进行方法的重写,因此在实例中就不会直接调用父类方法,如果需要调用,则需要在重写方法中用super()进行调用。

class Rectangle{//定义父类

       constructor(length,width){

              this.length=length;

              this.width=width;

       }

       getArea(){

              return "父类中抽象方法,未实现";

       }

}

class Square extends Rectangle{//定义子类

       constructor(length){//派生方法

              super(length,length);//通过super方法访问父类构造方法

       }

       //覆盖并遮蔽Rectangle的geArea()方法

       getArea(){

              return this.length*this.width;//在使用this之前,必须调用super

       }

}

var square=new Square(3);

console.log(square.getArea());//输出结果:是9,而不是父类中的getArea()方法的输出"父类中抽象方法,未实现"

如果要想在子类中使用父类的方法,则需要在重写方法中调用super()方法,如下

class Rectangle{//定义父类

       constructor(length,width){

              this.length=length;

              this.width=width;

       }

       getArea(){

              return "父类中抽象方法,未实现";

       }

}

class Square extends Rectangle{//定义子类

       constructor(length){//派生方法

              super(length,length);//通过super方法访问父类构造方法

       }

       //覆盖并遮蔽Rectangle的geArea()方法

       getArea(){

              return super.getArea();

       }

}

var square=new Square(3);

console.log(square.getArea());//输出结果:父类中抽象方法,未实现

(四)静态成员继承

    class Rectangle{//定义父类

              constructor(length,width){

                     this.length=length;

                     this.width=width;

              }

              getArea(){

                     return this.length*this.width;

              }

              static create(length,width){

                     return new Rectangle(length,width);

              }

       }

       class Square extends Rectangle{//定义子类

              constructor(length){//派生方法

                     super(length,length);//通过super方法访问父类构造方法

              }

              //覆盖并遮蔽Rectangle的geArea()方法

              getArea(){

                     return super.getArea();

              }

       }

       var rect=Square.create(3,4);//因为是静态方法,直接调用,不能实例化中调用

       console.log(rect.getArea());//输出结果:12

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部