Skip to content

Class 的基本语法

简介

  • ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到
  • 定义类方法的时候前面不需要加 function 关键字,且方法之间不用加都好分隔
  • 类的数据类型就是函数,类本身就是指向构造函数
class Point {
    // ...
}
typeof Point // "function"
Point === Point.prototype.constructor // true
  • 使用的时候直接对类使用 new 命令
  • 构造函数的 prototype 属性在类上面继续存在,事实上类的所有方法都定义在类的 prototype 上面 在类的实例上调用方法其实就是调用原型上的方法
class B {}
let b = new B();
b.constructor === B.prototype.constructor // true
  • Object.assign 方法可以很方便地一次向类添加多个方法
class Point {
    constructor(){
        // ...
    }
}
Object.assign(Point.prototype, {
    toString(){},
    toValue(){}
});
  • 类 prototype 对象的 constructor 属性,直接指向“类”的本身
Point.prototype.constructor === Point // true
  • 类的内部所有定义的方法,都是不可枚举的,这与 ES5 不一致
  • 类和模块的内部,默认就是严格模式

constructor 方法

constructor 方法是类的默认方法,通过 new 命令生成对象实例时,自动调用该方法。 如果没有显式定义,会默认添加一个空的 constructor 方法。constructor 方法默认返回实例对象(即 this )

类的实例对象

  • 与 ES5 一样,实例的属性除非显式定义在其本身(即定义在 this 对象上),否则都是定义在原型上(即定义在 class 上)
class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    toString() {
        return '(' + this.x + ', ' + this.y + ')';
    }
}
var point = new Point(2, 3);
point.toString() // (2, 3)
point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true
  • 类的所有实例共享一个原型对象
var p1 = new Point(2,3);
var p2 = new Point(3,2);
p1.__proto__ === p2.__proto__
//true
  • Object.getPrototypeOf 方法来获取实例对象的原型,然后再来为原型添加方法/属性

Class 表达式

  • 与函数一样类也可以使用表达式形式定义
const MyClass = class Me {
    getClassName() {
        return Me.name;
    }
};
  • 采用 Class 表达式,可以写出立即执行的 Class
let person = new class {}()

不存在变量提升

new Foo(); // ReferenceError
class Foo {}

私有方法

ES6 不提供私有方法,只能通过变通方法模拟实现

  • 在命名上加以区别
// 私有方法
_bar(baz) {
    return this.snaf = baz;
}
  • 将私有方法移出模块
class Widget {
    foo (baz) {
        bar.call(this, baz);
    }
}
function bar(baz) {
    return this.snaf = baz;
}
  • 利用 Symbol 值的唯一性,将私有方法的名字命名为一个 Symbol 值

this 的指向

类的方法内部如果含有 this ,它默认指向类的实例

Class 的取值函数(getter)和存值函数(setter)

与 ES5 一样,在“类”的内部可以使用 get 和 set 关键字,对某个属性设置存值 函数和取值函数,拦截该属性的存取行为。

Class 的静态方法

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前, 加上 static 关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

class Foo {
    static classMethod() {
        return 'hello';
    }
}
Foo.classMethod() // 'hello'
var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function
  • 如果静态方法包含 this 关键字,这个 this 指的是类,而不是实例
class Foo {
    static bar () {
        this.baz();
    }
    static baz () {
        console.log('hello');
    }
    baz () {
        console.log('world');
    }
}
Foo.bar() // hello
  • 父类的静态方法,可以被子类继承

Class 的静态属性和实例属性

静态属性指的是 Class 本身的属性,即 Class.propName ,而不是定义在实例对 象( this )上的属性。目前有一个静态属性的提案,对实例属性和静态属性都规定了新的写法。

  • 类的实例属性
class MyClass {
    myProp = 42
}
  • 类的静态属性
class MyClass {
    static myProp = 42
}

new.target 属性

该属性一般用在构造函数中,返回 new 命令作用的那个构造函数,如果构造函数不是通过 new 命令调用的会返回 undefined Class 内部调用 new.target 返回当前 Class,子类继承父类时会返回子类

Class 的继承

简介

Class 可以通过 extends 关键字实现继承。

  • 子类必须在 constructor 方法中调用 super 方法,否则在新建实例时会报错。这是因为子类没有自己的 this 对象 而是继承父类的 this 对象。

  • ES6 的继承机制实质是先创造父类的实例对象 this (所以必须先调用 super 方法),然后再用子类的构造函数修改 this 。

  • 如果子类没有定义 constructor 方法,会被默认添加并调用 super 方法

super 关键字

既可以当作函数使用也可以当作对象使用

  • 当作函数调用时,代表父类的构造函数,只能用在子类的构造函数中
  • 当作对象时,在普通当法中只想父类的原型对象,在静态方法中指向父类