33、class
什么是class
(1). 问题 旧js中每定义一种类型,都要定义两部分: 构造函数+原型对象。但是,旧js中,构造函数和原型对象在写法上是分离的。不符合封装的要求。 |
(2). 解决 今后,只要创建一种类型,都要用class{}包裹构造函数+原型对象方法。 |
(3). 什么是class 集中存储一个类型的构造函数和原型对象方法的程序结构。 |
(4). 如何: 3步 a. 用class{}包裹原构造函数和原型对象方法 b. 原构造函数名/类型名提升为class的名字,原构造函数必须更名为constructor。 c. 所有直接定义在class中的方法,默认都是保存在原型对象中的。 无需添加 也无需 |
(5). 其实class就是新瓶装旧酒,换汤不换药。虽然写法上改成了class和简化版,但是本质上还是构造函数+原型对象。创建子对象时,还是new 类型名(属性值列表); |
(6). 示例: 定义class保存学生类型的构造函数和原型对象方法:
3_class.html
<script> class Student{ //构造函数 constructor(sname,sage){ this.sname=sname; this.sage=sage; } //自动放入原型对象中保存 intr(){ console.log(`I'm ${this.sname}, I'm ${this.sage}`); } } var lilei=new Student("Li Lei",11); console.log(lilei); lilei.intr(); </script> | 运行结果: Student {sname: "Li Lei", sage: 11} I'm Li Lei, I'm 11 |
<script> function student(uname,uage){ this.uname=uname; this.uage=uage; } student.prototype.intr=function(){ console.log(`i'm ${this.uname}`); } var lilei=new student("lilei",11); console.log(lilei); </script> |
class中如何保存共有属性
问题 如果多个子对象共用的相同的属性值,应该放在那里? a. 旧js中,是和共有方法一起放在原型对象中 |
b. ES6 class中: 1). 问题 虽然直接在class中定义的方法,都默认保存在原型对象中。但是直接在class中定义的属性,却不会成为共有属性,不会保存在原型对象中。而是成为每个子对象的自有属性。 |
2). 解决 为了和其它主流开发语言尽量一致,ES6的class放弃了在原型对象中保存共有属性的方式。而是改为用静态属性保存! i. 什么是: 不需要创建子对象,单靠类型名就可直接访问的属性,就称为静态属性 ii. 何时: 今后,在ES6中,如果希望所有子对象,都可使用一个共同的属性值时,都要用静态属性代替原来的原型对象属性 iii. 如何定义静态属性: class 类型名{ ... ... iv. 如何访问静态属性: 坑: 错误: 正确: 类型名.静态属性 |
v. 原理 标有static的静态属性,都是保存在构造函数对象身上。因为构造函数在程序中不会重复!所以,静态属性,也不会重复!任何是否,任何地点,访问一个类型的静态属性,永远访问的都是同一份 |
vi. 示例: 使用静态属性替所有子对象保存共用的班级名
4.1_class_static.html
<script> //想定义学生类型,描述所有学生的统一结构和功能 class Student{ //定义静态属性className,可以全班同学共用一个 static className="初一2班" constructor(sname, sage){ this.sname=sname; this.sage=sage; } // className="初一2班" //不是共有,会变成自有属性 //默认保存在原型对象中 intr(){ console.log(`I'm ${this.sname}, I'm ${this.sage}, I'm from ${Student.className}`); } } //创建一个学生类型的对象 var lilei=new Student("Li Lei",11); var hmm=new Student("Han Meimei",12); console.log(lilei); console.log(hmm); lilei.intr(); hmm.intr(); //过了一年,两个学生都升级 Student.className="初二2班" lilei.intr(); hmm.intr(); console.log(Student);//不行!默认输出的是Student构造函数的函数体,不是对象结构 console.dir(Student);//不输出函数的内容,而是输出对象在内存中的存储结构 </script> 运行结果: |
<script> class Student { constructor(sname, sage) { this.sname = sname; this.sage = sage; } static className = "初一二班"; intr() { console.log(`你好,我是${this.sname}, 我今年${this.sage},我来自${Student.className}`); } } console.dir(Student); | |
var lilei = new Student("lilei", 11); console.log(lilei); |
两种类型间的继承
a. 问题 定义多个class时,发现多个class之间拥有部分相同的属性结构和方法定义。 |
b. 解决 今后,只要发现多个class之间包含部分相同的属性结构和方法定义时,都可以额外定义一个父类型class,替多个class集中保管相同部分的属性结构和方法定义。然后,再让多个class继承这个父类型class |
c. 如何: 2大步 1). 先额外定义一种新的class i. class名应该涵盖多个子集class的范围 ii. 多个class相同部分的属性结构,集中保存到父类型class的构造函数(constructor)中 iii. 多个class相同部分的方法定义,集中保存到付类型class中 2). 让子类型class继承父类型class 设置子类型的原型对象继承父类型的原型对象 i. class 子类型 extends 父类型{ ... } 扩展/继承 相当于Object.setPrototypeOf(子类型原型对象, 父类型原型对象); 但是,这样只能保证子类型的对象可以使用父类型class原型对象中的方法。依然无法为子类型的对象添加公共部分的属性结构。因为公共部分的属性结果不在父类型class的原型对象中,而是在父类型class的构造函数里。所以, ii. 还必须在子类型构造函数中,先调用super()关键字,自动调用父类型class中的constructor()构造函数,并自动执行父类型class的构造函数中的代码。结果父类型的构造函数将公共部分的属性结构,添加到子类型的对象身上。——结果: 最终子类型的子对象是由2个构造函数通力合作创建出来的。 |
什么是super 是extends附赠给我们的,自动代表父类型class中constructor构造函数的关键字。调用super()等效于调用父类型class中的constructor. 相当于执行{this.x=x;this.y=y} |
d. 示例: 定义class描述飞机大战游戏中的敌机和降落伞类型,同时避免属性和方法重复定义
4_class_extends.html
<script> //定义父类型class,替所有子类型class集中保管相同部分的属性结果和方法定义 class Enemy{ constructor(x,y){ this.x=x; this.y=y; } fly(){ console.log(`飞到x=${this.x},y=${this.y}位置`) } } //定义子类型继承父类型 class Plane extends Enemy{//仅继承原型对象 constructor(x,y,score){ super(x,y); //this.x=x; //this.y=y; this.score=score; } //自动就会保存进Plane原型对象中 getScore(){ console.log(`击落敌机得${this.score}分`) } } class San extends Enemy{ constructor(x,y,award){ super(x,y); this.award=award; } getAward(){ console.log(`击落降落伞,得${this.award}奖励`) } } //创建子类型子对象 var p1=new Plane(50,100,5); var s1=new San(20,80,"1 life"); console.log(p1); console.log(s1); p1.fly();//爷爷的 p1.getScore();//爸爸的 s1.fly(); s1.getAward(); </script> | 运行结果: Plane {x: 50, y: 100, score: 5} San {x: 20, y: 80, award: "1 life"} award: "1 life" x: 20 y: 80 __proto__: constructor: class San getAward: ƒ getAward() __proto__: constructor: class Enemy fly: ƒ fly() __proto__: Object 飞到x=50,y=100位置 击落敌机得5分 飞到x=20,y=80位置 击落降落伞,得1 life奖励 |