在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]