ES6 class

本文最后更新于:6 个月前

前言

classES6中引入的语法糖,其中的绝大部分的功能都可以使用ES5的方法做到。class可以看作是构造函数的另一种写法。

1
2
3
4
5
6
7
8
9
10
11
class myClass {
constructor() {
{
//...
}
}
}
// 等同于
var myClass = function () {
//...
}

class中的方法

class中定义方法,就相当于在原型对象上定义方法。

1
2
3
4
class B {}
const b = new B();

b.constructor === B.prototype.constructor // true

constructor方法

1
myClass.prototype.constructor === myClass

构造函数本身起到构造作用,使用class方法后,需要在类中引入一个constructor方法,该方法必须在“类”中存在,如果没有显式定义,引擎会自动为其添加一个空的constructor方法。

constructor默认返回实例对象即this,当然也可以如构造函数一样返回另外一个对象。

image-20210202200829671

如上图,当constructor方法返回一个对象,new命令执行后返回的就是该对象,当constructor有返回值,但是返回的不是一个对象时,默认返回的还是this实例对象。

class必须使用new命令调用,不能如构造函数般地直接调用。

constructor中定义的实例对象的属性,可以使用一种新的写法:

1
2
3
4
5
6
7
8
class foo {
bar = 'hello';
baz = 'world';

constructor() {
// ...
}
}

等同于:

1
2
3
4
5
6
class foo {
constructor() {
this.bar = 'hello';
this.baz = 'world';
}
}

静态

静态方法

class中的方法前加上static关键字,就说明该方法是静态方法,静态方法不会被实例对象继承,需要通过类来直接调用,静态方法中的this关键字指向类,而不是实例对象。

父类的静态方法可以被子类继承。

静态属性

定义在类上的属性。

1
2
3
4
5
class Foo {
}

Foo.prop = 1;
Foo.prop // 1

其他

new.target

  • 构造函数中使用:返回new命令调用的构造函数,如果构造函数不是使用new命令或者Reflect.construct()进行调用,则返回undefinded
  • 类内部调用:返回当前的类。

class注意事项

  1. class内部默认采用“严格模式”。
  2. 不存在“类”提升。
  3. 方法名前加*,表示这是一个Generator方法。
  4. this指向类的实例。

class 继承

class中的继承是通过extend关键字实现的。

但是ES6中的继承机制与ES5不同。

ES5中是先存在子类的this对象,然后将其绑定至父类的构造函数上,执行父类的构造函数,然后再执行子类的构造函数,之后再将子类的原型对象指向父类,将原型中的构造函数指向自己的构造函数。

ES6则是需要调用父类的构造函数,附带作用是生成一个this对象,之后才能在this上进行添加与修改。所以class中进行继承,在子类的构造函数中若是想使用this关键字,需要先调用super方法。

Super关键字

super关键字有两种用法:

  1. 作为函数:代表父类的构造函数,虽然代表父类的构造函数,但是调用父类的构造函数时,其中的this却指向子类实例,super作为方法使用时,只能出现在子类的构造函数中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class A {
    constructor() {
    console.log(new.target.name);
    }
    }
    class B extends A {
    constructor() {
    super();
    }
    }
    new A() // A
    new B() // B
  2. 作为对象:

    • 指向父类的原型对象:可以使用其调用父类原型对象上的方法,但是需要注意此时,方法中的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() // 2
    • 指向父类:可以使用其调用父类上的静态方法,此时this指向子类而不是子类实例。

prototype属性和__proto__属性

class 同时拥有这两个属性:

1
2
3
4
5
class A {
}

class B extends A {
}
  • 从构造函数的角度出发:B作为构造函数,B对应的原型对象的原型肯定是构造函数A的原型对象,这是在ES5中就成立的。

    1
    B.prototype.__proto__ = A.prototype;
  • 但是ES6中引入了静态方法,B继承了A的静态方法,AB可以直接调用静态方法,此时可以将其看作一个特殊的对象,那么对象是存在__prop__方法的,这时B的原型即为A

    1
    B.__proto__ = A;

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!