ECMAScript 2015 支援了 extends,至此 ECMAScript 能輕鬆實踐 Inheritance,但事實上也能由 Prototype Chain 實現。
Version
ECMAScript 2015
Extends
class Shape {
constructor(x, y) {
this.x = x
this.y = y
}
move(x, y) {
this.x = x
this.y = y
}
}
class Circle extends Shape {
constructor(x, y, radius) {
super(x, y)
this.radius = radius
}
draw() {
return `Drawing a Circle at ${this.x}, ${this.y}, Radius: ${this.radius}`
}
}
let circle = new Circle(0, 0, 5)
circle.move(10, 10)
circle.draw() // ?
以 class 實踐 OOP 最經典的 Shape。
此範例在 C++ 經常出現,後來 Java 與 C# 亦常常使用此範例
第 1 行
class Shape {
constructor(x, y) {
this.x = x
this.y = y
}
move(x, y) {
this.x = x
this.y = y
}
}
- 使用
constructor建立Shapeclass 的 constructor move()為Shape的 instance method
12 行
class Circle extends Shape {
constructor(x, y, radius) {
super(x, y)
this.radius = radius
}
draw() {
return `Drawing a Circle at ${this.x}, ${this.y}, Radius: ${this.radius}`
}
}
- 使用
extends繼承Shape - 使用
super()呼叫 parent class 的 constructor draw()為Circle的 instance method
22 行
let circle = new Circle(0, 0, 5)
circle.move(10, 10)
circle.draw() // ?
- 使用
new建立circleObject - 執行
move()與draw()instance method
這是完全 OOP 風格寫法,也再次證明 ECMAScript 為 multi-paradigm 語言,可完整實現 class-based 風格 OOP

儘管使用了 extends,但可發現 draw() 在 circle 的 Prototype Object 上,而 move() 在 Circle.prototype 的 Prototype Object 上,因為 extends 為 synatic sugar,所以完全看不到 Prototype Chain。
Prototype Chain
function Shape(x, y) {
this.x = x
this.y = y
}
Shape.prototype.move = function(x, y) {
this.x = x
this.y = y
}
function Circle(x, y, radius) {
Shape.call(this, x, y)
this.radius = radius
}
Circle.prototype = Object.create(Shape.prototype)
Circle.prototype.constructor = Circle
Circle.prototype.draw = function() {
return `Drawing a Circle at ${this.x}, ${this.y}, Radius: ${this.radius}`
}
let circle = new Circle(0, 0, 5)
circle.move(10, 10)
circle.draw() // ?
ES6 雖然提供 class 寫法,但骨子仍是 prototype,class 只能算 syntatic sugar。
第 1 行
function Shape(x, y) {
this.x = x
this.y = y
}
建立 Shape() constructor function,其中 this 指向將來 new 所建立的 Object。
因為使用 this,因此要使用 function expression。
第 6 行
Shape.prototype.move = function(x, y) {
this.x = x
this.y = y
}
在 prototype 上建立 move() instance method 以節省記憶體。
11 行
function Circle(x, y, radius) {
Shape.call(this, x, y)
this.radius = radius
}
建立 Circle() constructor function。
super() 要以 Shape.call() 實現,並將目前 Circle 的 this 傳入取代 Shape 本身的 this。
16 行
Circle.prototype = Object.create(Shape.prototype)
Circle.prototype.constructor = Circle
Prototype Chain 要實踐 Inheritance 關鍵在這兩行。
最直覺應該是將 shape Object 指定給 circle Object 的 __proto__ 即可實踐 Inheritance。
但目前尚未建立 Object,只能從 constructor function 下手,也就是將 Object 指定給 Circle.prototype。
因此使用 Object.create() 直接以 Shape.prototype 為 Prototype 建立 Object,然後再指定給 Circle.prototype 則完成 Inheritance。
但此時因為 Object 由 Shape.prototype 建立,其 constructor property 指向 Shape(),因此要以 Circle.prototype.constructor = Circle 修正其 constructor 為 Circle(),如此 circle Object 的 __proto__ 才能藉由 circle.constructor 找到 Circle() 與其 Prototype Object。
23 行
let circle = new Circle(0, 0, 5)
circle.move(10, 10)
circle.draw() // ?
一樣使用 new 建立 circle Object,用法完全一樣。

儘管由 extends 改成 Prototype Chain,但 circle 架構完全不變,也再次證明 extends 為 Prototype Chain 的 syntatic sugar。
Conclusion
- 兩種寫法的結果都一樣,也都建立了
circleObject,並呼叫move()與draw() - Class 寫法需使用
this、extends與super概念 - Prototype Chain 寫法需使用到
call(),尤其以 prototype 實現extends比較難懂