## 思维导图
一、基本写法
类的方法、属性、静态方法、静态属性、私有方法、私有属性
继承、接口(没有)、抽象(没有)、final(这个有)
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Student { constructor(name,age) { this._name = name this._age = age }
toString() { return `(姓名:${this._name},年龄${this._age})` } }
let s1 = new Student('小明','12') s1.y
|
构造函数constuctor
1 2 3 4 5 6 7 8 9
| class Student { constructor(name,age) { this._name = name this._age = age } toString() { return `(姓名:${this._name},年龄${this._age})` } }
|
实例属性
可以使用this.xxx写在constructor方法中,也可以写在类的顶端。
1 2 3 4 5 6 7 8 9
| class Student { _age = 12; constructor(name) { this._name = name } } let s1 = new Student('小欧') s1._name s1._age
|
实例属性不存在于原型链上,而是存在于单个实例中。如果constructor写了赋值,在创建实例时却没有赋值,那就会变成undefined拉
1 2 3 4 5 6 7 8 9 10
| class Student { _age = 12; constructor(name,age) { this._name = name this._age = age } } let s1 = new Student('小欧') s1._name s1._age
|
原型属性(使用prototype赋值)存在于原型链,用“类.prototype.属性名”可以调用到。
1 2 3
| Student.prototype.sex = '女' s1.sex s2.sex
|
类的方法是默认定义在原型链上,供所有实例共享的。但在类内部定义的变量是属于单个实例的,不存在与原型链上。
如果想在类外通过赋值的方法,定义属于原型链的属性,当然所有实例也都可以共享,但一旦修改所有实例的该属性都会修改,其实没有什么意义还容易出问题。所以虽然可以在原型链上定义实例,但一般来说没必要。除非真的确定这个属性在所有的实例上都是相同的。
getter、setter方法
在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
get/set方法定义的变量不需要提前定义。
set方法必须要传入value
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class JuniorStudent { _name = ''; _age = 0; _sex = '' constructor (sex) { this._sex = sex } get say () { return 'hi!' } set say (value) { console.log('say is'+value) } }
let js = new JuniorStudent() js.say = '111'
|
name
在类内部,可以使用类名.name去调用,获取类的名字
1 2 3 4 5 6 7
| class Me { getClassName () { return Me.name } } let m = new Me () m.getClassName ()
|
Class表达式
类可以用表达式的形式定义,在类外部调用时只能用表达式调用,如下面的例子,外部只能使用MyClass调用,但MyClass的实例还是属于Me
1 2 3 4 5 6 7
| let MyClass = class Me { getClassName() { return Me.name } } let mc = new MyClass() mc.getClassName ()
|
属性表达式
类的属性名可以用表达式表示
1 2 3 4 5 6 7 8
| let methodName = 'getString' let MyClass = class Me { [methodName]() { return 'getString' } } let mc = new MyClass() mc.getString ()
|
####静态属性
静态属性定义在类上,不在实例上,所以只能用类名.属性名调用。
定义静态属性的方法是在class外部,用类名.属性定义该属性
1 2 3 4 5
| class Foo { } Foo.prop = 1; Foo.prop
|
es6的规定,class内只有静态方法,没有静态属性,但现在有个提案是用static在内部定义静态属性,所以也可以如下定义
1 2 3 4 5 6 7
| class Foo { static fooString1 = 'string1' } let foo = new Foo() foo.fooString1 Foo.fooString1
|
静态方法的定义:
1 2 3 4 5 6
| class Foo { static pringString = function (str) { return str } } Foo.pringString('111')
|
私有方法和私有属性
使用#定义私有属性。只能在类的内部使用(this.#count),无法继承,无法在外部调用。
暂时没有提供私有方法。
1 2 3 4 5 6 7 8
| class MyClass { #name = 'aaa' constructor () { this.name = this.#name } } let mc = new MyClass() mc.name
|
####静态块
有时候在类内部有一部分代码,是不用每次创建实例时都去调用的,比如静态属性的赋值。
所以es2022规定了静态块,在类生成时只执行一次,主要用于对静态属性的赋值,之后新建实例就不再运行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class C { static x = ...; static y; static z;
static { try { const obj = doSomethingWith(this.x); this.y = obj.y; this.z = obj.z; } catch { this.y = ...; this.z = ...; } } }
|
new.target
该属性一般用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令,new.target会返回undefined
1 2 3 4 5 6 7 8 9 10 11 12
|
function Person(name) { if (new.target === Person) { this.name = name; } else { throw new Error('必须使用 new 命令生成实例'); } }
var person = new Person('张三'); var notAPerson = Person.call(person, '张三');
|
##二、类的继承
1 2 3 4 5 6
| class Person { } class Student extends Person { }
|
super方法与super关键字
1. super方法
super方法可以且只能在子类构造函数中调用,用来调用父类的constructor(),在子类的构造函数中必须要调用一次super()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Person { constructor (x,y) { this.x = x this.y = y } } class Student extends Person { constructor (x1,y1,newstring) { super(x1,y1) this.newstring = newstring } } let s1 = new Student(1,2,'str') s1.x s1.newstring
|
2. super关键字
super作为对象时,在普通方法中,指向父类的原型对象(Point.prototype);在静态方法中,指向父类。
由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的。
因为类中定义的方法本就是定义在原型链(prototype)上,所以super可以调用到类内的方法。但super没办法调用到类内的变量,因为类中定义的变量是存在于实例的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class A { constructor() { this.p = 2; } }
class B extends A { get m() { return super.p; } }
let b = new B(); b.m
|
在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class A { constructor() { this.x = 1; } print() { console.log(this.x); } }
class B extends A { constructor() { super(); this.x = 2; } m() { super.print(); } }
let b = new B(); b.m()
|
在子类的静态方法中通过super调用父类的方法时,方法内部的this指向当前的子类,而不是子类的实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class A { constructor() { this.x = 1; } static print() { console.log(this.x); } }
class B extends A { constructor() { super(); this.x = 2; } static m() { super.print(); } }
B.x = 3; B.m()
|