JS 的原型繼承(方法2)-Object.create()

前言

先前的筆記中已經談到了用function constructor來建立物件,同時也提到這個概念是模仿其他程式語言來的,然而其他的程式語言會用class這個關鍵字來設定物件的模板(tamplate),然後用new來建立物件,這是古典繼承/類別物件導向的程式語言;而 JavaScript始終是一個原型繼承/原型物件導向語言,所以即使看起來很像,本質上是不同的。

因此有許多人認為專注在JS中的原型繼承而不要使用古典繼承會是個好選擇。
而JS中還有一個沒有模仿其他程式語言的建立物件方法,它就是等等我們要談的Object.create()


Object.create() 使用

首先,我們先使用這段程式碼建立一個物件的原型

1
2
3
4
5
6
7
var Person = {
firstName: 'Default',
lastName: 'Default',
getFullName: function () {
return this.firstName + " " + this.lastName;
}
}

然後建立一個以Person為基礎的物件

1
2
var john = Object.create(Person);
console.log(john);

輸出的結果如下,它是一個空物件,但是它繼承了 Person 這個物件當中的屬性和方法:


  • 透過 Object.create() 可以建立一個空物件,同時可以將帶入Object.create() 的參數內容變成該物件的原型。
  • Object.create()是最單純使用原型繼承prototypal inheritance的方式,使用 Object.create() 的方式運用繼承和原型的概念能夠非常簡便的建立物件。

實際應用

如果你想要定一個物件的原型,就先建立一個 A 物件當做其他物件的基礎,然後再建立另一個空物件 B,指稱 A 物件當做它的原型,再透過為 B 物件賦予屬性或方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
var A = {
firstName: 'Default',
lastName: 'Default',
getFullName: function () {
return this.firstName + " " + this.lastName;
}
}

var B = Object.create(A);

B.firstName = 'John';
B.lastName = 'Doe';
console.log(john.getFullName());

對於 firstNamelastName來說,在 B物件就已經有這兩個屬性,因此它不會在往該物件的原型__proto去尋找,而對 getFullName 來說,因為在 B這個物件裡沒有這個方法,於是就會到 __proto__ 裡面去找,最後會回傳"John Doe"

關於這個概念考可以參考之前的筆記了解JavaScript中原型(prototype)、原型鍊(prototype chain)和繼承(inheritance)的概念


若瀏覽器不支援

雖然大部分的新瀏覽器都支援這個語法,但如果某些瀏覽器的版本真的舊到無法使用 Object.create() 的話,可以怎麼辦呢?
我們可以利用函數建構子 與「new」的方式新增這個功能。

使用polyfill

polyfill: 有一些舊型瀏覽器引擎不支援某些JavaScript功能,因此有人會自己撰寫一些程式碼來實作相同效果的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
// polyfill for Object.create()

if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) {
throw new Error('Object.create implementation only accepts the first parameter');
}

function F() {};
F.prototype = o;
return new F();
};
}

分析程式碼

  1. 首先先判斷瀏覽器支不支援,如果瀏覽器中查無Object.create會回傳布林值false,再由!運算子轉換成true,觸發if內程式碼。
1
if (!Object.create) { ... }
  1. 由於瀏覽器不支援,所以我們要在JS引擎內建的 Object() 函數建構子內,自己創造一個名字一樣為create的方法。
1
Object.create = function (o) { ... }
  1. 如果 Object.create = function (o) { ... } 的傳入參數 o 超過一個以上,console回報錯誤訊息。
1
2
3
if (arguments.length > 1) {
throw new Error('Object.create implementation only accepts the first parameter');
}
  1. 建立一個名為 F 的函數建構子。
1
function F() {};
  1. F建構子的prototype當中新增一個物件,該物件是之後使用者回傳入的參數 o
1
F.prototype = o;
  1. 回傳一個以F函數建構子為基礎,並以new創造的物件,且該物件的__proto會繼承F.prototype內的物件( 也就是使用者傳入的參數o ),如此一來能夠達到Object.create()的原始效果。
1
return new F();

資料來源