iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 16
2
Modern Web

JavaScript基本功修煉系列 第 16

JavaScript基本功修練:Day16 - 原型的基本概念

  • 分享至 

  • xImage
  •  

終於跑完一半鐵人賽了,接下來會慢慢深入JavaScript比較進階的部分(嚇怕。這兩三天會進入原型的課題,而今天就先整理一下原型的基本概念。

原型是什麼?

我們可以把原型想像成一個藍圖
例如我們想建一台車,就會想到一台車會包括以下的特性:

  • 車的種類 (電動車、貨車、摩托車...)
  • 車的顏色 (紅色、黑色、藍色...)
  • 車的坐位數目

這就是一台車的藍圖,但它只是一個藍圖,並不是實實在在的一台車。接下來我們要實際建出一台車,就可以按這份藍圖去建起來,例如:

上圖可見我們建了兩台車,同樣是按車的藍圖去做出來,這裏反映出一些概念:

  • 我的車子跟你的車子無關係,是兩樣不同的物件,各自按自己的喜好調整屬性值
  • 我的車子和你的車子共同繼承了同一個藍圖

同一個函式建構子,產生不同實體物件

上文提及我們用車子的藍圖,產生出一台實際的車。在JavaScript裏面,我們可以用「函式建構子」來代表那個藍圖,再用new的運算子,產生出一個實體物件(myCar、yourCar),如以下的程式碼:

//建立函式建構子
function car(type,color,person){
    this.type = type;
    this.color = color;
    this.person = person;
}

//之後用函式建構子來產生實體物件
var myCar = new car('電動車', '紅色',4)
var yourCar = new car('貨車','藍色',2)

函式建構子

針對這個例子,在討論myCaryourCar之前,我們先看看函式建構子car有什麼特別,我們可以用console.dir(car)去找出這個原型:

上圖可見,函式建構子裏面有一些屬性:

  • 函式裏有prototype屬性
  • 這個prototype屬性裏面,再有2個屬性:
    1. constructor屬性
    2. __proto__屬性

constructor屬性,就是指回自己這個函式建構子的本身,即是car這個函式。__proto__屬性是什麼呢?就是這個函式再上一層的原型,就是object,因為function是屬於object型別。

實體物件

那麼兩個由同一個函式建構子產生的實體物件呢?我們用console.log(myCar)console.log(yourCar)查一下:

__proto__打開,會發現它們都有同一個constructor屬性,這不意外,因為它們都是由同一個函式建構子產生的。

我們可以總結一下實體物件的特別之處:

  • 物件裏有__proto__,裏面有:
    1. constructor屬性
    2. 有一個__proto__屬性

剛才已經解釋過第一個了,那麼第二個屬性__proto__呢?明明已經有了__proto____proto__裏面還要包多一個__proto__,到底是什麼意思呢?這裏的__proto__是指向它的原型,就是carprototype

拿出裏面__proto__car函式建構子的prototype屬性比對一下來證明:

聰明的你會發覺這些東西就是一個連著一個,沒錯,這個關係就是原型鏈的概念。聽起來很複雜?我們可以把整個原型鏈關係想像成下圖這樣:

為什麼要理解原型鏈或原型?

看到這裏,你可能會問為什麼要學這樣煩的關係?因為我們可以透過修改原型,來產生更多有一堆相同屬性的實體物件。

就如剛才提及車的例子,試想想我要建100台車,然後裏面都是重複有那3個屬性,我就是重複寫100次,吃掉很多記憶體。但是,如果那100台車都是在共用同一個原型,那個原型裏已經寫好那3個屬性,那只會佔很少記憶體。例如以下例子,我想要增加drive這個方法:

//在函式建構子的prototype裏新增drive的方法
car.prototype.drive = function(){
  console.log(`我可以駕駛${this.type}`)   
}

//myCar本身沒有drive方法,但JavaScript會找尋上一層原型,找到drive方法
myCar.drive() //我可以駕駛電動車
yourCar.drive() //我可以駕駛貨車

以上可見,我只要在carprototype加上drive方法,之後那些物件就能繼承去用那些方法。

我們這時候再查一下myCaryourCar:

以上就更清晰可以見到,myCaryourCar的原型都被加入了drive方法。注意,如果我們之後想修改原型的屬性或方法,最好的做法就是回到建構子去改,並不是任意找一個物件,再指定它的原型去改,這樣會使後續維護更麻煩更易出錯。

總結

  • 可以用函式建構子建立一個原型(藍圖)
  • 利用函式建構子產生出不同實體物件。這些物件都是共用同一個函式建構子(原型)
  • 物件之間的原型繼承關係,稱為原型鏈
  • 在指定物件的屬值或呼叫方法時,如果在該物件裏找不到那個值或方法,JavaScript便會往上層原型去找

参考資料

JS 原力覺醒 Day21 - 原型
重新認識 JavaScript: Day 24 物件與原型鏈
JavaScript 核心篇 (六角學院)


上一篇
JavaScript基本功修練:Day15 - 解構賦值的概念與應用
下一篇
JavaScript基本功修練:Day17 - 建立一個多層原型鏈
系列文
JavaScript基本功修煉31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言