終於講完物件導向的章節了,今天我們就要來講講繼承 ( Inherit ),簡單來說從一個原始版本的 class 來衍生出更多特殊版本的 class,這就叫做繼承。
子層類別會擁有父層類別的所有屬性、方法,再加上自己定義的屬性、方法
,所以我們可以說子層類別也就是父層類別的延伸,由於 JavaScript 屬於 prototype-based 的物件導向語言,藉由將現有 object 做為 prototype 的方式來達成繼承功能。
看到這裡,可能有些朋友會覺得很複雜。沒錯。前面章節提到的原型與日後會提到的繼承可以說是 JavaScript 較複雜的兩個概念,但許多 JavaScript 的強大功能與彈性,也都來自於其物件結構與繼承,所以說是非常值得花時間去了解其運作的原理哦!
call - 顧名思義就是呼叫函式,不過可以透過 call 傳入的第一個參數來改變 this,後續的參數就當作一般參數做傳入。
函式名稱.call(改變 this 物件, 參數 1, 參數 2, ....) => 執行函式
apply - apply 與 call 的差別在於後續參數會是一個陣列。
函式名稱.apply(改變 this 物件, 陣列) => 執行函式
bind - bind 大致上與 call 相同,但它會產生新的函式。
函式名稱.bind(改變 this 物件)(參數1, 參數 2, ...) => 新函式
如果想對這三個函式有更深入了解的朋友,我在下方也會提供參考資料哦!
現在,就讓我們用一些程式碼來理解他的使用吧!
// 使用 call 呼叫函式,傳入參數並且修改 this
function show(a, b) {
console.log( this, a, b);
}
show(5,10); // Window, 5, 10
show.call({}, 5, 10); // {}, 5, 10
// call, apply, bind 程式碼比較
function show() {
console.log( this, arguments );
}
show.call({name: "Reynold"}, 2, 3) //
show.apply({name: "Reynold"}, [2, 3]); //
show.bind({name: "Reynold"})(2,3); //
// 三個函式的呼叫結果都相同,皆是 {name: "Reynold"}, Arguments(2)[2,3]
以上都是介紹它們的使用方式,下面我們就來看日常情境題吧!
// 透過 call 繼承屬性與方法
function A() {
this.abc = 12;
this.run = function() {
console.log("go");
};
};
function B() {
A.call(this);
}
var obj = new B();
console.log(obj.abc); // 12
obj.run(); // go
使用 new 建立物件時,也等同於
var obj = {};
B.call(obj);
以上就是透過 call 來繼承屬性與方法,大家要記得一個觀念
繼承物件時,父層類別所擁有的屬性與方法,子層類別也必定同時擁有相同的屬性與方法。
看到這裡,可能會有些朋友覺得,為什麼 call 能夠繼承屬性與方法呢?
老話一句,欲知後事如何,且待下回分解 XDDD
在剛懂得繼承時,常常為了使用而使用,後來才發現,根本只是在浪費自己的時間,不過看過的程式碼越來越多、專案也越來越大之後,漸漸就會發現使用繼承的時間點,如果各位讀者發現你開始再建立許多類似功能的多個物件時,你就可以先建立一個通用的物件,來去涵蓋所有共有的功能,再去建立特定的物件繼承這些功能,並針對這些物件去給予各自所需的功能,這樣既方便又能提高效率哦!
參考資料:
Tommy - 深入 JavaScript 核心課程
MDN - JavaScript 中的「繼承」
MDN - Function.prototype.call()
MDN - Function.prototype.apply()
MDN - Function.prototype.bind()