在ES2015标准之前,我们利用函数原型来实现类:

function Animal(family, specie, hue) {
    this.family = family
    this.specie = specie
    this.hue = hue
}
Animal.prototype.yell = function() {
    console.log(this.hue)
}

var doge = new Animal('Canide', 'Canis lupus', 'Wong')
doge.yell() //=> Woug

ES2015类定义语法:

class Animal { // 类定义
    constructor(family, specie, hue) { //构造函数
        this.family = family
        this.specie = specie
        this.hue = hue
    }

    yell() { // 方法
        console.log(this.hue)
    }
}

const doge = new Animal('Canidae', 'Canis lupus', 'Woug')
doge.yell() //=> Woug

类方法内的第一层所引用的this指向类实例,如果方法内包含箭头函数,则引擎会根据包含层级把箭头函数内引用的this所指向的实际对象一直向上层搜索,直到达到一个函数作用域或块级作用域为止。

类继承语法:
经典JavaScript教材中,都有提到多钟在JavaScript中利用对象原型所实现的类机制要如何做到类的继承。比如通过组合继承、原型式继承、寄生式继承和寄生组合继承。Node.js官方标准库中也提供了一种继承方式:

import { inherits } from 'util'

function Point2D(x, y) {
    this.x = x
    this.y = y
}
Point2D.prototype.toString = function() {
    return `(${this.x}, ${this.y})`
}

function Point3D(x, y, z) {
    Point3D.super_.call(this, x, y)
    this.z = z
}
inherits(Point3D, Point2D)
Point3D.prototype.toString = function() {
    return `(${this.x}, ${this.y}, ${this.z})`
}

const point2d = new Point2D(2, 3)
const point3d = new Point3D(1, 4, 3)

console.log(point2d.toString())
console.log(point3d.toString())

ES2015的类继承方法相对简单许多:

class Point2D {
    constructor(x, y) {
        this.x = x
        this.y = y
    }

    toString() {
        return `(${this.x}, ${this.y})`
    }
}

class Point3D extends Point2D {
    constructor(x, y, z) {
        super(x, y)
        this.x = x
    }

    toString() {
        return `(${this.x}, ${this.y}, ${this.z})`
    }
}

需要注意的是,子类的constructor构造函数中必须使用super函数调用父类构造函数后才能使用this,否则会报this is not defined的错误

Getter/Setter:

class Point {
    constructor(x, y) {
        this.x = x
        this.y = y
    }

    get d() {
        // Euclidean distance: d = (x^2 + y^2)的开方
        return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2))
    }
}

const p = new Point(3, 4)
console.log(p.d)

静态方法:
以下示例使用静态方法,在定义子类时,以实现固化一些参数的目的:

class Animal {
    constructor(family, specie, hue) {
        this.family = family
        this.specie = specie
        this.hue = hue
    }

    yell() {
        console.log(this.hue)
    }

    static extend(constructor, ..._args) {
        return class extends Animal {
            constructor(...args) {
                super(..._args)
                constructor.call(this, ...args)
            }
        }
    }
}

const Dog = Animal.extend(function(name) {
    this.name = name
}, 'Canidae', 'Canis lupus', 'Woug')

const doge = new Dog('Doge')
doge.yell() //=> Woug
console.log(doge.name) //=> Doge

toString:
在ECMAScript中所有的对象都有一个名为toString()的方法,这个方法是被定义在Object底层类上的。在Object类及其子类实例中,有一个利用Symbol.toStringTag作为键的属性,它定义着当这个对象的toString()方法被调用时候,所返回的Tag的内容是什么

class Foo {
    get [Symbol.toStringTag]() {
        return 'Bar'
    }
}

const obj = new Foo()
console.log(obj.toString())  //=> [object Bar]

你可能感兴趣的:(类)