第十次社課
物件導向「超」入門
資管系ㄉ惡夢 YuSheng
JS ㄉ this
延伸閱讀
最好回家ㄉ時候慢慢讀
該來理解 JavaScript 的原型鍊了
淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂
this 的值到底是什麼?一次說清楚
看完上面後 強烈 推薦 必看!!!!
物件導向入門之概念篇
NOTE:首先我們先來講為什麼要物件導向呢
其實大家一般寫程式的方式也是可以
你可以不斷的寫長長的程式
然後定義很多個函數
很多個變數
那你就會發生一個情況就是你的程式到處散落
假設你在寫一個大型的遊戲
你可能有玩家的物件
然後你有敵人的物件
這些物件的屬性 雖然你可以把它包成一包
但是你有非常多的函數
這些函數有可能是主角攻擊阿
或是怎麼樣改變分數
然後或是我輸出敵人的血量等等這些動作
那當這些函數沒有辦法
跟我們剛剛所說到的資料整合在一起的時候
它們就會全部散亂在你的畫面跟程式裡面
所以當你合作溝通的時候
會變得非常麻煩
NOTE:你剛寫完時看你自己的程式
會看起來 好像還看得懂
然後很有規則
但是別人看你的程式就會像一團亂七八糟的義大利麵
或是你兩個月回來看自己寫的程式
如果你沒有物件導向的概念
你沒有把資料跟方法綁定在一起
你會非常的難管理自己的開發
什麼是物件導向?
在控制程式的時候
以物件為「概念」來包裝
NOTE:所以我們先來問一件事情
什麼是物件導向
物件導向其實就是我們在控制程式的時候
我們用物件為概念
來包裝我們所有的邏輯跟操作
NOTE:所以我們要分為三個步驟
第一個步驟 把情境描述為物件
那接下來就是描述物件的屬性跟行為
然後接下來就是操作物件 讓它們彼此互動
把問題描述為物件
NOTE:我們現在舉一個很簡單的例子
這個例子是
我今天 A 這個藍色的人
要給 B 一根香蕉
我們如果要把問題描述為物件
我們就可以看出這個情境裡面
有兩個人在跟一根香蕉做互動
所以我們知道物件有人跟香蕉
描述物件的屬性跟⾏為
NOTE:那接下來呢
我們要來描述物件的屬性跟行為
我們可以看到
人有很多基礎的屬性阿
比如說名字 年齡 我現在有什麼物品
然後人也可以有很多的動作
像是打招呼
走路 或接受物品
或送出別人物品這些動作
那接下來香蕉也可以有很多屬性
比如說它的名字價格味道
或是香蕉可以被剝皮 或是攻擊別人
那這樣子我們定義完物件之間的動作之後
我們就可以去呼叫這些動作
或者讓物件呼叫彼此的動作
操作與讓物件彼此互動
NOTE:如果要達成讓 A 這個藍色的人
送給 B 一根香蕉要怎麼做呢
首先我們先要知道
A 跟 B 他都屬於人這個概念
所以我們可以定義人類這個類別
人類有很多事情 有很多屬性嘛
但是我們要有一個實體
那現在實體的案例就是 A 跟 B
它們兩個都屬於人這個類別
那接下來 A 這個人有一根香蕉
香蕉也是一個實體的物品
那接下來我們要做的事情就是
我們去呼叫物件上面的動作
或是去存取它的屬性
假設 A.打招呼
然後 A 就會說話
然後 A.給予香蕉
這個給予香蕉的動作
我們可以給它一個參數
那我們就傳給它 B
所以 A 就把香蕉給 B
那接下來 B 去呼叫香蕉.剝皮
因為它想要吃它
然後最後再用 B.吃(香蕉)
來讓 B 把香蕉吃掉
所以你可以注意到整個
現在描述的情境裡面
幾乎沒有出現程式碼
或是我沒有去敘述底層的說
打招呼裡面到底在做什麼
它是要輸出 hello 我的名字嗎
或是什麼之類的
或是我沒有描述說
B.吃(香蕉) 它裡面可能
它把它吃了一口
然後它去研究說香蕉是什麼味道
或是描述香蕉怎麼樣
我只把所有的動作
包裝在吃香蕉這個抽象的概念裡面
然後去呼叫 B 的行為
那你可以注意到在這件事情裡面
我們所有的概念
它都被包裝為一層物件來做互動
所以我們並不會感受到說
如果要完成一件打招呼這件事情
我們就要寫好幾行說
先定義它要講什麼事情
然後我去輸出這一串文字
而是我可以去呼叫這個類別
這個人上面類別預設的行為
那像你一般打招呼
你可能是說 hello 我是誰誰誰
那我就定義人這個類別 在打招呼的時候
它就是輸出 hello 我是
然後輸出人這個本身的名字
NOTE:所以你可以注意到在這個動作裡面
總共做了兩件事情
第一個事情是根據類別產生物件
也就是說我們先定義了人這個類別
可以做什麼 以及它有什麼屬性
然後接下來以人為基礎產生了 A
跟 B 這兩個實體的人
然後我們就稱為兩個物件
所以抽象的部分是類別
實體產生出來的東西是物件
而物件是根據我們給它的初始資料
做出來的
但它具有我們類別裡面
所有相關的屬性跟可以執行的動作
那接下來我們就去做操作物件的動作
不管是我們去直接呼叫 A 跟 B 的屬性
或方法
或是我可以讓物件呼叫彼此的動作
那像剛剛的例子裡面
我們定義了人的類別 產生了 A 跟 B
然後也讓 A 跟 B 彼此呼叫像打招呼
或者讓 A 呼叫香蕉的剝皮等等
案例:票務系統
NOTE:那我們來講一個實體一點的案例
剛剛大家可能會覺得有點抽象
假設我今天在賣演唱會的票
那這張演唱會的票 實際上可能會有它是什麼票種
然後它的價格是多少
折扣是多少 手續費是多少
然後接下來它的方法
也就是這個物件的操作方法
我可能需要取得它的售價
要用它的總價乘以折價來算
那或者我會需要購買
購買可能就是把它的所有人填上你的名字
那退票後續可能會有一卡車的手續
但是我知道它用退票這個方法可以呼叫
那或者我列印狀態
把這張票券的類似綜合資訊列印出來
案例:票務系統
NOTE:我們想要一下我們之前會怎麼做
之前我們可能會定義票務
那票務的話 我們有票的價錢
票的種類
票的 discount 票的折價
以及票的 fee 它的手續費
所以我們會注意到在這個情況裡面
舊的方法我會去定義
ticket 開頭的一堆變數
然後我們去說
有個 function 是 get_ticket_price
我們把四個變數傳進去
讓它計算最後的結果給我
或者 get_ticket_description
去有點像綜合敘述這一個
那我去輸出一個 根據這些資料算出來的一串文字
那接下來我們之前也有講到說可以把
ticket 包成一個物件
所以你可以注意到阿
前面這些是它的屬性
然後以及下面這些是它的方法
一個物件有屬性跟方法組成
案例:票務系統
NOTE:那接下來第二階段
我們之前學過物件的打包
所以現在我們把 price type discount 跟 fee
都包在 ticket 這個物件裡面
那接下來我們就可以直接在方法的部分
把 ticket 傳進去
所以我們就不會像剛剛一樣
分了好多個變數
我們還要去每次都要記得要傳哪些
我就把這個物件傳進去
而裡面這個方法就自動呼叫 A
這個物件上面的價格
折價等等來做計算
這個是第二階
那第三階也就是我們剛剛說的
我們要做到物件導向
所以起碼做的事情是什麼
我們需要把 function 也就是方法
跟這一個資料這一包整理在一起
所以我們必須要產生一個物件
它裡面有屬性 有這些資料
也有方法可以呼叫
有這些 function 可以呼叫
那這個 ticket 我們最理想最理想的情況就是
有沒有辦法讓它直接吃到本身的屬性
所以我就不用再給它任何的參數給它計算
我直接讓它呼叫自己的參數就好
NOTE:所以我們看一下怎麼抽象形容這個問題
我們希望有一個票券的物件
那這個票券的物件我們會事先定義說
物件有哪些屬性 像剛剛的價格
接下來我們定義說這個物件上面有哪些可用方法
那我們會希望這個方法
可以去呼叫自己想要的屬性來做計算
或者做其他的事情
那接下來第三個 怎麼樣去產生這個物件
所以這一個動作就叫做定義類別
NOTE:那我們根據類別來產生物件的時候
它的基礎語法是這樣子
我們 var 一個 Ticket
那這個 Ticket 通常習慣第一個字大寫
來當作物件的類別
這就是抽象的概念
那接下來我們等於一個 function
那我們可以傳初始值進去給它
那接下來這個 function 執行的時候
它就會回傳自己
而這個自己就是我們剛剛所說的
有屬性 有方法的物件
那接下來我們可以用 this.屬性
來設定這個物件上面的初始值
那以及 this.方法
來設定它可以執行的方法
那在這個方法裡面呢
我們一樣可以使用 this.屬性 this.方法
來存取自己的屬性
或是它可以做的事情
雖然這樣講有點抽象
JS中的函數打包 - 類別定義
NOTE:我們直接看一個實體的程式案例
在 js 裡面函數打包的類別定義
這邊我們已經做了一個完整的 Ticket 物件
那產生這個票券物件的時候
我們這個 Ticket 是類別
我們會等於一個 function 有點像產生器去產生物件
那產生物件的時候
我必須要給它的是它的價格以及它的折價
那接下來產生價格
有了價格跟折價之後
我在初始化的時候
也就是設定這個物件的時候
我們會設定 this.price this.type
一些它上面應該有的屬性
我們屬性可以直接指定給
現在傳進來初始的價格以及折價
那接下來我們去用 this.get_price
跟這個定義說這個物件可以執行什麼動作
那這個動作裡面呢 假設我們 get_price
我們是要去算說它的總價
我們就可以直接存
this. 總價乘以它的折價
再加上這個物件上面的手續費
所以我們就達成了說 把方法
跟數值整合在一起這件事情
JS中的函數打包 - 產⽣物件
NOTE:那接下來怎麼樣產生一個物件呢
就像剛剛人這個類別
我們需要產生 A 跟 B 這兩個實體的人
那它們才能做互動
所以我們剛剛用了 function 來定義物件嘛
接下來如果我們要產生一個實體的物件
我就 var 一個 myticket
這一張票會等於
新的 Ticket
我們用新的類別來把它定義出來
所以它意思其實就是
我執行了 Ticket 這個函數
然後傳進去我們初始值 然後 new 一個
所以我們現在最後得到的就會是
一個新的物件
然後它具有 ticket 上面所有的屬性
但是它現在在 ticket 的 price
跟 discount 部分 填的是我傳給它的初始值
JS中的函數打包 - 操作物件
NOTE:那接下來我們就可以讓這個物件做互動了
比如說我們讓 myTicket,price 我們就會得到 500
myTicket.discount 就會得到 0.5
然後 fee 之類的也是
那接下來我們可以呼叫這一個 myTicket
實體出來的物件上面的方法
比如說我們 .get_price
它就會回傳 530
然後我們 .get_description 就會回傳我們剛剛那一串文字
或者說我上面有定義如何退票的話
我可以直接傳給它我需要退幾月幾號的票
然後會拿回多少的錢
那這樣子的話
我就不用再去碰這個物件裡面複雜的邏輯
所以這樣子呢 我就可以輕易地達成說
如果這個物件是由其他人建立的
我可以不用管退票這件事情裡面怎麼做
不管它有沒有呼叫伺服器
然後有沒有去計算它應該退回多少金額等等
我只要傳給它 它需要的東西
比如說它到底要退哪張票
然後它就會傳給我一些
比如說退票的結果
NOTE:所以我現在就有一個票券物件
可以完整的操作
那我們這個動作就稱為封裝
那我們就不用再碰裡面的邏輯
那這樣子不僅很方便維護
而剛剛那樣子的寫法
比如說我們呼叫物件上面的動作或屬性
也很好的 很直觀的能夠理解
物件導向入門之繼承篇
NOTE:物件導向入門的繼承篇
在前一個單元裡面我們有提到
如果我們今天把方法以及屬性
包在同一個物件裡面
我們就可以通過物件的互動
來寫更抽象簡潔的程式
那這邊會有個小小的問題
因為我們的方法是在物件產生的時候
加在這個物件上的
即使我們可以使用這些方法
NOTE:但是假設我們今天用 people
人類這個類別產生了三個人
叫做 Mark Marry 跟 John
那比如說我有一個方法叫 say hello
那它會輸出 Hello I'm 誰誰誰
那在這個問題就會存在說
因為我們是在產生物件的時候 放在上面的函數
所以這些函數都是獨立存在於物件內的
也就是這些黃色的部分
那當我們 比如說我們想要統一改動
人類打招呼的方式
從 Hello I'm Marry 變成 Hi I'm Marry 的時候呢
我們就必須要一個一個改物件
這樣子其實就會有點麻煩
所以我們的問題是
函數存在於產生的物件內 而無法共用
NOTE:所以如果我們想要共用函數的話呢
我們必須要先使用 prototype
prototype 是什麼呢
它其實是 js 中物件導向的一種實現方式
那也就是說我們不在裡面說
this.方法 等於什麼
因為這些方法都一樣
我們不希望重複的放在產生的物件內
那接下來我們就會希望說
如果我們想要呼叫某些特定的方法
就可以定義在 Ticket.prototype 的上面
定義在 prototype 的上面的時候
原型它不會被複製進去物件
所以它不會產生很多份放在新產生的物件裡面
而是物件它會有個參考
連結到這個原型
在找不到屬性的時候
就會來這個 prototype 上面看看有沒有
那我們來看一下圖解的部分
NOTE:我們剛剛所新增的 prototype
其實就是一個共同參照用的原型
那這個參照用的原型它會獨立存在在外面
那比如說當我們根據人類的類別
產生了這三個人之後呢
裡面並不會有這些原型的 function
比如說 say hello 我們就不會放在這個地方
而是它會有個連結連到 prototype
所以比如說我們 Mark.sayHello 的時候
它就會說 Mark 上面沒有 sayHello 耶 怎麼辦
它去找它的 prototype 上面有沒有
然後它就找到 sayHello
那這個 prototype 裡面
你一樣可以使用 this. 誰誰誰的屬性
和 this. 方法
也都呼叫的到這個物件上面的東西
所以我們就達到了
可以統一管理這些函數的目的了
那既然我們可以統一管理這些函數
NOTE:我們要怎麼樣去看更進階的物件導向呢
剛剛其實我們之前的單元都在講說
怎麼樣讓物件有自己的屬性
跟方法 然後封裝在一個物件裡面
但是我們接下來要講的是繼承
繼承其實有點像 prototype 的概念
它是去延伸概念與物件
比如說我想要把生物延伸成植物與動物
因為植物跟動物都是生物
NOTE:所以我們現在要做的事情是
如果我可以把類別延伸成新的類別
會有什麼優勢呢
第一就是減少重複地程式
我們可以用抽象的概念做進一步的延伸
比如說生物延伸成人或狗
因為人或狗都是生物
可能都有它生命的長度阿
今年幾歲阿
或是它會吃東西等等
那這些我們就不應該重複的寫在人跟狗裡面
所以我們應該怎樣去做繼承呢
NOTE:比如說我今天生物體
有名字 生命長度這兩個屬性
還有移動跟吃東西的方法
假如我想要定義一個狗怎麼辦
你可以想像啦
這個繼承它有點像包一層殼在外面
所以我基於生物體這個類別
我再包一層狗
然後狗的話有自己的品種
喜歡吃的東西
那也會有一些狗有的動作
像吠叫或攻擊
但是我今天使用這整包狗的類別的時候呢
它也會包含我繼承來生物體的名字跟生物長度
我就不需要重複定義名字跟生命長度
這些基礎的屬性了
而這樣子繼承有什麼好處呢
我們可以把這個生物體拿去延伸成其他類別
比如說我今天要新增一個龍的類別
那龍也一樣屬於生物
有自己的名字跟生命長度等等的
但是龍會飛
龍會飛翔也會生蛋
然後有自己的火焰強度跟和善程度
所以我們就基於相同的
生物體的這個高層級的類別
延伸成兩個比較低層級的狗跟龍
分別有自己的屬性了
NOTE:你可能會問我要怎麼
用在程式跟遊戲裡面呢
你可以注意到
我今天在玩遊戲的時候啊
每一個遊戲角色它都會有共用的生命值
跟位置這兩個東西
那這些角色有生命值跟位置之後呢
我們去繼承這個角色
延伸成三種類型
NPC 玩家跟敵人
那 NPC 可能有一些自動控制的方法阿
玩家有一些物品欄位
然後敵人有掉寶機率
所以這也就是繼承了角色延伸成敵人
那敵人也可以使用角色裡面所有屬性跟方法
接下來你也可以做第二層的繼承
你可以把一般的魔物
跟魔王這兩種敵人拆出來
那一般的魔物我們會指定它的出現區域
然後魔王的話會有一些特殊技能
或特殊的屬性設定
所以這樣子就可以幫助我們很有效的去管理
我們裡面的物件模型
而避免說我每個物件裡面有重複的部分
比如說我每個都重複寫了生命值跟位置
而導致我的程式變的很肥大
NOTE:那在 js 裡面怎樣去繼承呢
這邊大家要先搞清楚
我們說的繼承其實都是類別跟類別之間的繼承
那這樣子的話呢
我們剛剛講的 new function
先定義完類別
然後再 new 出來產生一個實體
比如說這張圖的動作
我根據狗的類別
new 出來產生一個 poppy 這隻小狗
那今天我們講的繼承其實就是在上面
我們在定義這個類別的時候呢
我們再額外指定它的母類別是什麼
比如說我們讓狗繼承生物
那在 js 裡面
它的繼承方式就會是有點像連結
所以說我今天根據這個狗
有繼承生物產生出來的這個 poppy
這個實體的物件的話
假設我呼叫吃東西這個方法
那就會找找找找找 找到
狗裡面沒有吃東西啊
那如果說你有指定繼承的時候
它就再繼續往上找
找到上游的原型
那這個原型呢
裡面如果你有定義吃東西 它就會執行
這個好處就會是說 假設你想要
複寫掉這個方式的時候會很方便
比如說狗雖然也有吃東西
但它吃東西的方法可能比較不一樣
只有狗專屬的吃東西的方式
那我就會在定義狗的時候
再定義一個它的吃東西
當我們在執行一個 poppy.吃東西 的時候呢
我們是定義在 prototype 裡面
因為不是物件裡面 所以它會說物件裡面沒有
然後接下來找到 prototype
當它找到狗上面吃東西的時候
它就會執行狗上面的吃東西
然後不會繼續往上找
所以它就會以最近的這個 function
也就是繼承的層次
最下面的這個函數為主
NOTE:如果要搞懂繼承的話
我們就要知道
類別是產生一個新的物件
而 prototype 是獨立於類別跟物件之外的
當物件有寫共用屬性的時候
就會往上查找到 prototype
而我們剛剛講的原型鏈
也就是繼承的方式
我們必須要讓狗可以使用生物體
它的一些方法或屬性的時候呢
我們就讓 prototype 的上游再一個 prototype
所以它就會不斷的往上查找方法
屬性直到找到可以使用為止
所以大家應該了解繼承的這整個概念了
那我們要怎麼樣定義
也就是在程式碼中實作繼承呢
NOTE:總共就是三個步驟
第一個是建立的時候呼叫母類別
第二個子類別新增的時候繼承 prototype
第三個將建構函數指向自己
那這看起來有點難
NOTE:我們直接進到說明的部分
首先第一件事情是我在建立這個物件的時候
我也要呼叫母類別的建構函數
什麼意思啊
你可以看到
我們之前的那個建構函數 那個 function
我們定義 this.attr
這個物件上面的屬性等於什麼東西
所以當我們希望這個物件
同時有繼承來生物體的屬性的時候
其實最簡單的方式就是把這個物件
丟進生物體的初始化函數嘛
那丟進這個初始化函數
我們必須要用一個特殊的方式
我們比如說 我們這邊用 Parent
就是繼承的這個母類別 .call
那 call 的方式就是呼叫函數
呼叫什麼函數呢
我拿 this 也就是這個物件來呼叫
所以你可以想像我們今天有點像偷樑換柱一樣
我們把現在正在用的這個物件
當做 this 傳進去給生物體讓它初始化
所以它就不會重複的產生出來兩個新物件
而是我們會在 比如說你看這邊
我們先定義一個 Creature 也就是生物這個類別
然後它的一些初始化函數
那我們定義了一個 Dog
也就是繼承了生物的狗
然後我們在第一行我們就讓它 Creature.call
this 跟一些引數
所以在這邊生物體就把它拿來初始化了
而初始化的是這個目標 是 this
那這個 this 就是指向你
狗產生出來的這個新物件
所以不管是狗這個物件
狗正在新增的這個物件
還是生物體正在新增的這個物件
我都指向同一個這個東西
所以我們最後產生出來的結果就會是
我用狗的方式
設定完了一遍這個物件
也用生物體的方式設定完了這個物件
那也要注意一下順序是說
我會希望先有生物體的屬性嘛
所以我先用 Creature.call
然後接下來這一個初始化執行完之後呢
我們再去設定狗相關的屬性
NOTE:那接下來我們來講第二個
為子類別新增繼承的 prototype
甚麼叫做為子類別新增繼承呢
假設我們希望狗
可以用生物體的移動或吃東西的方法
那最簡單的方式 你會問說
為什麼我不把生物體的 prototype 指定給狗就好了
因為物件會自動往上找嘛
它就會找到生物的 prototype
那其實我們會發現一個問題是
因為我們想要對狗也要做一些
單獨的 prototype 設定
狗也有一些共用的函數 是只有狗有的
所以假設我現在定義一個吠叫或攻擊
而我沒有一個中繼的 prototype
我直接連到生物的 prototype 的時候呢
因為我定義在 prototype 上
所以我就會動到生物的這個物件了
所以要怎麼做
我們必須要使用 Object.create
Object.create 它是創造一個空的新的物件
但是將它的上游
連到你給它的 prototype
所以我們用比如說生物跟狗的案例呢
我們讓 Dog.prototype
這個狗的原型會等於 Object.create
一個空的物件
然後我們傳給它 Creature.prototype
所以這一個空物件上游連結了一個原型鏈
一個 prototype 是生物的
所以你可以想像中間被產生出了一個空的物件
但是有這個虛線存在
讓我們找不到方法的時候
可以回溯的上游去呼叫生物的方法
所以這樣產生出來之後
我們把它指定給 Dog.prototype
NOTE:那最後一件事情呢
就是把建構函數指向自己
我們想像我們在定義類別的時候
都會定義一個新的 function 嘛
那這個 function 假設我們今天用 Object.create
做了一個新的空物件的時候
它也會往上找阿
可是它找不到這個 constructor
也是我們定義的這個產生函數的時候呢
它就會繼續找 找到生物的 prototype
上面的產生函數
所以就變成了
它會用生物的那個產生函數
來初始化我的物件 而不是狗的這個
所以我們必須要讓 Child.prototype.constructor
比如說我們讓狗的 prototype 的建構函數
會等於狗的建構函數
這樣子呢
它才不會繼續往上游回溯的生物的建構函數
NOTE:那這樣大家聽下來應該已經整個茫掉了
最後講一下實際範例是人的繼承
我們想要先做一個人的物件 Person
那這個 Person 有一些基礎的像名字 年齡 打招呼
那我們希望延伸這個人類的物件呢
新增一個 Worker 工作者的物件
那這個工作者的物件有工作種類
薪水跟工作的自我介紹
它會說我的名字是什麼 我的工作是什麼
所以它會用到上游的這個名字
那也會用到自己的這個 工作種類
那這邊我們看一下
我們首先 var 一個 Worker
它會等於一個 function 先初始化整個產生函數
那在裡面我們做的第一件事情 因為我們要繼承人
所以我們讓 Person.call(this.name)
所以我們這邊呼叫人的建構函數
然後我們把什麼傳給它建構呢
我們把這個正在新增的物件傳給它
也就是 this
然後我們傳給它這個人啊
我們之前人不是用個名字來初始化嗎
所以我們就後面函數的參數一樣接給它
那接著呢 新增完人的屬性之後
我們去設定 this.job
就是這個 Worker 上面的一些屬性
那新增完這個之後
第二件事情是 prototype
所以我們讓 Worker.prototype 這個工人的原型
會等於 Object.create
我們創造一個新的物件
連結到上游的 Person.prototype
所以這現在是空的 但是有那個連結存在
然後最後我們讓 Worker.prototype,constructor
也就是這個工作者的建構子
就是那個產生的函數呢
會等於自己的產生函數
所以我們讓它不會再上游回溯到人的產生函數
那做完這個長長的繼承之後
我們就可以來做 Worker.prototype.tellJob
我們在 prototype 上面定義我們最一開始提到的共用函數
所以我們 tellJob 等於 I am 然後 this.job
然後我們也可以在 比如說在後面接一個
my name is "this.name"
那它也一樣可以吃到這個繼承來的 Person 的名字
那最後就跟我們之前一樣
我們產生一個新的 Worker
var Henry 會等於 new Worker
然後給它名字跟它的工作
它就會自動初始化那個 Person 的類別
然後繼承過來
那最後我們就可以讓 Henry.sayHello
或是 Henry.tellJob
不管是人上面的打招呼
或是 Worker 上面的自我介紹都可以呼叫
物件導向入門之實作篇
NOTE:https://codepen.io/yu_sheng/pen/rNazzxx?editors=0010
NOTE:在前面
我們講了如何使用物件導向
來把屬性跟方法綁在一起
以及繼承其他類別的東西
產生一個更進階的類別
那在這裡
我們會用物件導向的思維
來寫一個球球對打的小遊戲
那這個小遊戲裡面
兩個板子會互相對打
這個大家應該蠻熟悉的
那在這個遊戲裡面的話呢
我會有幾個主要的物件
NOTE:包括板子跟球
那這兩個板子跟球 你可以想像
它都是在遊戲的畫面裡面
所以它會有自己的位置 元素跟大小
所以我們會有一個遊戲物件當成母類別
分別有位置 元素跟大小
以及一些方法 像更新 css
把位置跟大小更新到實際的網頁上面
以及會有一個函數叫做 Collide
去偵測有沒有碰撞
我們可以傳給它另一個物件
然後讓它跟我們說
這兩個物件是不是有重疊
那接下來我們會延伸繼承這個遊戲物件
變成球跟板子兩個類別
在球的部份我們會加上一個速度的屬性
然後我們會有一個 Update 更新
它除了執行母類別的更新 css 之外呢
也會把速度加到位置上面
所以你可以想像球就會連續的移動
那以及球會有一個初始化的函數
裡面會讓它有亂數的初始速度
以及把它放到畫面中央
那接下來在板子的部份呢
我們沒有加上屬性
不過我們的 Update 更新
我們會檢查它是不是有超出邊界
那如果有超出邊界 就限制它的移動
所以它不會超出遊戲的範圍
然後最後它也會呼叫母類別的更新 css
把資料反應到現在的網頁上面
NOTE:那接下來是遊戲本體的部分
在遊戲本體我們也會建立一個物件
一個類別來記錄它
包括計時器
去呼叫每一個當下的那一個遊戲更新
以及 Control
我現在鍵盤按的狀態
然後分數
那以及一些方法 像是開始 結束遊戲
然後初始化我的鍵盤控制
以及遊戲本體更新的那個迴圈
那我們會藉由遊戲這個物件呢
來控制板子跟球的行為
NOTE:我們來看一下實際上的程式碼大概會長這樣子
定義一個遊戲物件
然後我們藉由這個縮放的功能
我們可以很清楚的看到
遊戲的物件上面有哪些方法可以呼叫
以及我在初始化遊戲物件的時候呢
要傳進去什麼樣的參數
NOTE:那這邊也是球 我們去繼承了遊戲的物件
那我們在球上面加上了 Update
跟初始化這兩個額外的方法
NOTE:那以及 Board
我們也是傳進去繼承遊戲物件之後呢
我們再加上一個 Update
去檢查有沒有超過邊界跟更新
NOTE:然後最後我們會有個總體的遊戲
那這個遊戲呢
我會有它的計時器 以及剛剛所講的
開始 結束遊戲等等的控制
所以你可以注意到用物件導向的方式來寫程式
我們可以讓程式碼非常好管理 而且一目了然
NOTE:那我們先講一下尺寸資訊的部分
我們整個遊戲場地是 500500
然後裡面的東西用絕對定位
針對這整個方框做定位
所以我們上面這個板子距離上面 30
下面這個板子的上距是 455
然後每個板子是 10015 的尺寸
然後最後球是 1515
那了解尺寸資訊之後呢
我們就可以開始進到物件導向的實作