這個老虎機練習主要考察JavaScript中的原型鏈(prototype
)和this
關鍵字的使用。
主要思路
-
創建三個輪盤(reels)實例:我們需要創建3個獨立的輪盤對象,它們都委托(delegate)到基礎的
reel
對象。這可以通過Object.create(reel)
來實現,創建新對象并將其原型指向reel
。 -
實現
display()
方法:這是最復雜的部分,需要顯示3×3的網格:- 每個輪盤需要顯示三個位置:當前位置、上方位置和下方位置
- 行顯示(水平方向):以"|"分隔的三個輪盤符號
- 列顯示(垂直方向):每個輪盤的三個位置(上中下)
實現代碼
function randMax(max) {return Math.trunc(1E9 * Math.random()) % max;
}var reel = {symbols: ["?", "?", "?", "?", "?", "★", "?", "?"],spin() {if (this.position == null) {this.position = randMax(this.symbols.length); }this.position = (this.position + 100 + randMax(100)) % this.symbols.length;},display() {if (this.position == null) {this.position = randMax(this.symbols.length);}return this.symbols[this.position];}
};var slotMachine = {reels: [Object.create(reel),Object.create(reel),Object.create(reel)],spin() {this.reels.forEach(reel => {reel.spin();});},display() {// 獲取每個輪盤上方、當前和下方的符號var lines = [];// 創建三行(上、中、下)for (let linePos = -1; linePos <= 1; linePos++) {let line = this.reels.map(reel => {// 創建一個臨時對象,委托到reel,但擁有自己的positionvar slot = Object.create(reel);// 調整position以顯示上方/當前/下方的符號slot.position = ((reel.position + linePos) + reel.symbols.length) % reel.symbols.length;return slot.display();});lines.push(line.join(" | "));}// 打印結果console.log(lines.join("\n"));}
};slotMachine.spin();
slotMachine.display();slotMachine.spin();
slotMachine.display();
代碼解析
-
循環創建三行:使用
-1
、0
、1
作為偏移量,分別表示上、中、下行 -
顯示每個位置的符號:
- 為每個位置創建一個臨時對象(使用
Object.create(reel)
) - 調整臨時對象的
position
屬性,考慮到循環(使用模運算) - 調用臨時對象的
display()
方法獲取符號
- 為每個位置創建一個臨時對象(使用
-
處理循環邊界問題:當計算上方位置(特別是當前位置為0時),需要加上
reel.symbols.length
來確保結果為正,然后再取模 -
格式化輸出:組合所有符號,map生成的行數組用"|“分隔轉換成字符串后加入lines數組,lines數組用換行符”\n"分隔轉換成字符串。
-
spin()
方法有兩個主要作用:-
初始化位置:如果輪盤的
position
屬性為null
(比如第一次使用時),它會為輪盤設置一個初始隨機位置。 -
改變輪盤位置:每次調用
spin()
都會使輪盤旋轉一定數量的位置(至少100個位置加上0-99的隨機數),然后通過取模確保最終位置在有效范圍內。在示例代碼中:
slotMachine.spin(); slotMachine.display(); // 顯示第一組結果slotMachine.spin(); slotMachine.display(); // 顯示第二組結果
兩次結果不同,正是因為中間調用了
spin()
方法,改變了每個輪盤的位置。如果刪除第二個spin()
調用,兩次display()
會顯示完全相同的結果。所以
spin()
方法是整個老虎機機制的核心部分之一,它模擬了真實老虎機拉桿后輪盤旋轉的過程,而這個旋轉直接決定了最終顯示的符號組合。
-
-
reel
原型對象-
reels
數組中的對象:reels: [Object.create(reel),Object.create(reel),Object.create(reel) ]
這里創建了三個獨立的對象,每個都作為
slotMachine
的一個輪盤。這些對象在整個slotMachine
的生命周期中持續存在,并且每個都維護自己的position
屬性狀態。當我們調用slotMachine.spin()
時,這三個對象的position
屬性會被更新。 -
display()
方法中的臨時對象:var slot = Object.create(reel); // 這個是個臨時對象,不是reels中的元素
這是在
display()
方法內部創建的臨時對象,它在每次顯示時創建,用完即丟棄。這個臨時對象不是用來替代輪盤的,而是用來臨時保存修改后的位置,以便顯示上方或下方的符號,而不影響原始輪盤的position
屬性。理解這一點很關鍵:
slot
是通過原型鏈委托到reel
對象的,而reels
數組中的每個元素是通過原型鏈委托到同一個reel
對象的獨立對象。因此,它們在內存中是完全不同的對象,只是共享相同的原型。這種結構讓我們能夠在不改變原始輪盤位置的情況下,顯示每個輪盤的上方、當前和下方位置的符號。
-
-
理解參數
reel
的來源:-
this.reels.map(function getSlot(reel){...})
中的reel
參數是map
方法傳入的,它代表的是this.reels
數組中的每個元素,也就是我們在slotMachine
初始化時創建的那三個輪盤對象。 -
然后,我們基于這個輪盤對象創建一個臨時對象:
var slot = Object.create(reel)
,這個臨時對象的原型是當前遍歷到的輪盤對象,而不是原始的reel
對象。 -
這樣,我們可以通過
reel.position
訪問到當前輪盤的位置,并在臨時對象中設置調整后的位置:slot.position = ...
。
簡單來說,這里存在三層委托關系:
slot
對象委托到reels
數組中的特定輪盤對象- 那個輪盤對象又委托到原始的
reel
對象 - 當我們調用
slot.display()
時,會使用slot
自己的position
,但方法本身是從reel
原型繼承的
-