iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 29
0

今天來看看其他建立物件的方法

除了new建構子和物件實體語法,JS還有別種建立物件的方法,那就是ES5新增的Object.create和ES6新增的類別class

先來看Object.create,以下為程式碼:

var Flash = {
	firstname: '預設值',
	lastname: '預設值',
	run: function(){
		return 'Run,' + this.firstname + ',Run!';
	}
}
var Barry = Object.create(Flash);
console.log(Barry);

首先用物件實體語法創建物件並以變數Flash指向它。
接著使用使用Object.create()方法並傳入Flash當參數,並以變數Barry指向它。
現在用console.log印出Barry,結果是:

真的只是一般的空物件嗎?
點開瀏覽器console印出的這個空物件

我們可以看到,Barry(指向的)這個物件,它的原型是Flash物件。
也就是說

Object.create()這個方法建立物件,傳入給它的參數會成為創建出物件的原型

這種模式的好處,在於可以給物件屬性設定預設值,例如現在的Barry空物件,如果取用firstname和lastname屬性會發生什麼事?

console.log(Barry);
console.log(Barry.firstname);
console.log(Barry.lastname);

結果是:

Barry物件明明是空物件,為何還可以顯示出東西?別忘記當物件存取不存在的屬性與方法時,會透過原型鏈向物件原型查找,可以看第25天筆記回顧。

如果想要隱藏預設值,只要設定同樣的屬性、方法覆蓋過去就好:

Barry.firstname = 'Barry';
Barry.lastname = 'Allen';
console.log(Barry.run());

Object.create是ES5以後新增的語法,某些舊版瀏覽器並不支援(例如IE8),這時我們可以用polyfill來處理。

polyfill

有些舊版引擎會缺少開發者要用的程式語法,開發者可以用程式檢驗JS引擎(瀏覽器)是否有目標程式語法,如果沒有就由開發者撰寫程式添加進去。

如果要幫瀏覽器手動添加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();
	}
}

說明
先用if判斷Object.create是否存在,如果對if()內放Object.create這種寫法感到困惑,可以看第10天筆記回顧。

如果Object.create不存在,就將一個函式表示式(並傳值o)賦予給Object.create。若賦予Object.create的函式傳入參數超過1個以上,就報錯。

接著設定空函式F,將o傳入F的prototype,最後if陳述句回傳一個物件,這個物件是用new函數建構子建立,原型為函式F的物件。

以上就是手動設定Object.create的程式寫法,但現在是2018年,主流瀏覽器應該都支援Object.create,就當是作者在影片的補充技巧吧。
 
 


接著是ES6新增的class類別介紹,來看看以下程式碼:

class TheFlash{

	constructor(firstname, lastname){
		this.firstname = firstname;
		this.lastname = lastname;
	}

	run(){
		return 'Run,' + this.firstname + ',Run!';
	}
}

var Barry = new TheFlash('Barry', 'Allen');
console.log(Barry);

我們設定一個class類別TheFlash,在裏頭有constructor建構子,和函式建構子一樣,我們可以預先設定物件值,也可以設定函式方法在class裏頭。

設定好class,要創建新物件仍然使用new並帶入參數,參數會對應到constructor的設定,以此創建物件,故上面程式碼,console.log結果是:

在其他的語言,類別是創建物件的藍圖,但在ES6,類別本身是被建立出來的物件class TheFlash是一個實際被建立的物件,開發者是從物件建立新物件,也就是說,ES6的JS,本質仍然是原型繼承,而非變成古典繼承。

那class要怎麼設定原型呢?可以使用ES6新增的extends來處理。
(注意:不是第26天介紹的underscore.js函式庫extend,是extends,字尾多了一個s)

延續class TheFlash程式碼,在程式碼下面新增另一個class:

class SpeedRunner extends TheFlash{

	constructor(firstname, lastname){
		super(firstname, lastname);
	}
}
var RedRunner = new SpeedRunner('Barry', 'Allen')
console.log(RedRunner.run());

設定類別SpeedRunner並extends TheFlash(extends會繼承類別TheFlash),在constructor內,透過super方法去獲得父類別TheFlash的建構式參數設定。

RedRunner此時的父類別是類別TheFlash,它能透過原型鏈取用方法run()嗎?
來看看結果

 
 
 
 
小結
class語法本質上還是JS原型繼承,也就是所謂語法糖,extend(擴展、繼承)的概念也很容易在現今JS框架中看到,例如Vue.js容易見到extend、React容易見到extends,可以說JS的框架都是以JS原型繼承的概念為基礎並加以擴展的。

今天的筆記內容可以參照Udemy課程:JavaScript 全攻略:克服JS的奇怪部分5-63、5-64


上一篇
Day28 內建的函式建構子
下一篇
Day30 心得-持續學習、持續成長
系列文
JavaScript基礎二三事30

尚未有邦友留言

立即登入留言