[英]How to pass argument value from one module to another?
我正在嘗試為 Tic Tac Toe 游戲實現功能。
const "startModule" - 玩家應該能夠在開始屏幕上輸入 select X 或 O。
然后該值應分配給參數“playerChoice” ,我正試圖將其傳遞給“gameModule”。
在“gameModule”中,“playerChoice”參數被分配給“circleTurn”。
基於“circleTurn 值,腳本應將 css 值(“X_CLASS”或“CIRCLE_CLASS”)分配給“handleClick”function 中的“currentClass”參數。這是不起作用的地方。
我還在學習,希望得到任何幫助或指點:)
編輯:我從之前的 js 部分刪減了很多,只留下了大量信息(我希望如此)
const startModule = (() => {
let xButton = document.getElementById("player-choiceX")
let oButton = document.getElementById("player-choiceO")
let playerChoice;
const xoChoice = () => {
xButton.addEventListener('click', function(e){
playerChoice = false;
document.getElementById("playerChoice").style.display = "none";
console.log(playerChoice);
})
}
return {
xoChoice, playerChoice
};
})();
const gameModule = (() => {
const board = document.getElementById("board");
const X_CLASS = 'x';
const CIRCLE_CLASS = 'circle';
const resetButton = document.getElementById("reset");
const winningMessageElement = document.getElementById("winningMessage");
const cellElements = document.querySelectorAll("[data-cell]");
const winningMessageTextElement = document.querySelector("[data-winning-message-text]");
let circleTurn = playerChoice
const WINNING_COMBINATIONS = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
]
const startGame = () => {
resetButton.addEventListener('click', startGame);
cellElements.forEach(cell => {
cell.classList.remove(X_CLASS)
cell.classList.remove(CIRCLE_CLASS)
cell.removeEventListener('click', handleClick)
cell.addEventListener('click', handleClick, {once: true})
})
setBoardHoverClass()
winningMessageElement.classList.remove('show')
}
const handleClick = (e) => {
const cell = e.target
const currentClass = circleTurn ? CIRCLE_CLASS : X_CLASS
placeMark(cell, currentClass)
if (checkWin(currentClass)){
endGame()
} else if(isDraw()) {
endGame(true)
} else {
swapTurns();
setBoardHoverClass();
}
}
}
return {
startGame, handleClick
}
})();
startModule.xoChoice()
gameModule.startGame()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="styles.css">
<script src="index2.js" defer></script>
<title>TicTacToe</title>
</head>
<body>
<div class="player-choice" id="playerChoice">
<div class="xOrCircle">
<div class="player-choiceX" id="player-choiceX"></div>
<div class="player-choiceO" id="player-choiceO"></div>
</div>
</div>
</div>
<div class="board" id="board">
<div class="cell" data-cell></div>
<div class="cell" data-cell></div>
<div class="cell" data-cell></div>
<div class="cell" data-cell></div>
<div class="cell" data-cell></div>
<div class="cell" data-cell></div>
<div class="cell" data-cell></div>
<div class="cell" data-cell></div>
<div class="cell" data-cell></div>
</div>
<div class="winning-message" id="winningMessage">
<div data-winning-message-text></div>
<button id="reset">Reset</button>
</div>
</body>
</html>
所以我想指出一些關於你所擁有的東西。
為了便於解釋,我將重寫您的startModule
以使其更易於理解
const startModule = (() => {
let playerChoice;
const xoChoice = () => {
playerChoice = false;
};
return {
xoChoice, playerChoice
};
})();
基於此版本的startModule
,檢查以下代碼的輸出:
startModule.playerChoice; // undefined
startModule.xoChoice();
startModule.playerChoice; // undefined
好的,那playerChoice
沒有變成 false 出了什么問題? 它與稱為按值傳遞和按引用傳遞的東西有關(更多信息請參見 此處)
基本上,因為playerChoice
被分配了一個原始值( undefined
),當它在這里返回時:
return {
xoChoice, playerChoice
};
return 語句只返回原始值undefined
,而不是 Object 的引用。
幸運的是,有一個解決方法,即利用 Javascript 中的傳遞引用功能。
如果不是用原始值 ( undefined
) 存儲playerChoice
並返回它,我們可以用模塊的必要上下文存儲一個 Object。 這應該有效,因為對象是按引用傳遞的,而不是按值傳遞的。 這個代碼看起來像這樣:
const startModule = (() => {
let context = {
playerChoice: undefined
}; // This is a JSON Object!
const xoChoice = () => {
context.playerChoice = false;
};
return {
xoChoice, context
};
})();
現在讓我們看一下基於此版本的 startModule 從以下代碼輸出的內容:
startModule.context.playerChoice; // undefined
startModule.xoChoice();
startModule.context.playerChoice; // false
有用! 之所以如此,是因為我們返回的是 Object ( context
),所以我們返回的是對存儲位置的引用(據我所知:)),而不是返回沒有引用的原始值(例如undefined
、 false
)到存儲的地方。 所有這些意味着調用playerChoice
function 時更改的xoChoice
與首次調用startModule
playerChoice
相互關聯的。
好的,那么您如何利用此信息在模塊之間共享playerChoice
的值? 為了回答這個問題,我將再次簡化gameModule
以使事情更容易理解。
const startModule = (() => {
// ... (What we previously had)
})();
const gameModule = (() => {
let circleTurn = context.playerChoice;
return {
circleTurn
};
})();
和以前一樣,讓我們運行一些代碼看看發生了什么:
startModule.context.playerChoice; // undefined
gameModule.circleTurn; // undefined
startModule.xoChoice();
startModule.context.playerChoice; // false
startModule.circleTurn; // false
所以你是 go,使用傳遞引用我們能夠將數據從一個模塊 ( startModule
) 傳輸到另一個 ( gameModule
)!
歡迎提出任何其他問題,如果您願意,我可以向您展示另一種有趣的替代編碼方式。
編輯:這是有趣的(不是更好或更壞)替代方式。 使用以前的方法,您運行了一個 function,它完成了所有這些工作,返回了一個信息豐富的 JSON Object,您可以向其中檢索信息,例如正常的 JSON Object。與其讓 startModule 成為startModule
的返回值,不如將 startModule 簡單地分配給startModule
,您可以JSON Object,具有做東西的功能(之前的東西)作為 Object 的值。它看起來像這樣:
const startModule = {
playerChoice: undefined,
xoChoice: function () {
// 'this' references the 'startModule' Object
this.playerChoice = false;
}
}
如您所見, startModule
現在是 JSON Object,但仍具有與以前相同的所有組件。 閱讀有關this
關鍵字的信息很重要,因為它與 this alternative 密切相關。 (僅供參考,如果您使用箭頭函數,則永遠不會分配this
關鍵字,因此如果您想使用this
,請確保使用 ES5 函數)。
讓我們看看下面的代碼及其 output:
startModule.playerChoice; // undefined;
startModule.xoChoice();
startModule.playerChoice; // false
一切似乎都運行良好。 雖然playerChoice
最初是undefined
的,但調用xoChoice
成功地將值變為false
。
現在這個替代方案有一個小問題。 比如說當你創建startModule
時你想要自動執行一些邏輯(也許你想發出 HTTPS 請求來檢查用戶的 Tic Tac Toe 連勝記錄,也許你想檢查用戶是否登錄,等等)。 為此,通常的做法是將init
分配給startModule
,並將該值分配給執行初始邏輯的 function。 它看起來像這樣:
const startModule = {
playerChoice: undefined,
xoChoice: function () {
// 'this' references the 'startModule' Object
this.playerChoice = false;
},
init: function () {
// do initialization stuff
this.userLoggedIn = true;
}
}
現在顯然,我們需要在分配startModule
后立即運行startModule.init()
。 這是一個更優雅的解決方案:
const startModule = {
playerChoice: undefined,
xoChoice: function () {
// 'this' references the 'startModule' Object
this.playerChoice = false;
},
init: function () {
// do initialization stuff
this.userLoggedIn = true;
return this;
}
}.init();
在這里,我們一創建 Object 就調用init
,但是因為init
返回this
,我們仍然可以將startModule
分配給這個 function 調用。
現在讓我們看看gameModule
的可能實現:
const gameModule = {
board: document.getElementById("board"),
X_CLASS: 'x',
CIRCLE_CLASS: 'circle',
resetButton: document.getElementById("reset"),
winningMessageElement: document.getElementById("winningMessage"),
cellElements: document.querySelectorAll("[data-cell]"),
winnningMessageTextElement: document.querySelector("[data-winning-message-text]"),
circleTurn: startModule.playerChoice, // look for the playerChoice value in the startModule Object
WINNING_COMBINATIONS: [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
],
startGame: function () {
// 'this' references the Object this function lives under
this.resetButton.addEventListener('click', this.startGame);
this.cellElements.forEach(cell => {
cell.classList.remove(this.X_CLASS)
cell.classList.remove(this.CIRCLE_CLASS)
cell.removeEventListener('click', this.handleClick)
cell.addEventListener('click', this.handleClick, {once: true})
})
setBoardHoverClass() // idk where this func comes from
this.winningMessageElement.classList.remove('show')
},
handleClick: function (e) {
// etc...
}
}
通過此實現,我們所有的變量都存儲為鍵值對,我們使用this
來引用它們所在的 Object 並檢索它們的值。 您還可以在circleTurn
的值中看到我們使用startModule.playerChoice
從startModule
獲取playerChoice
值。
我希望我知道這兩種不同實現的技術名稱,但就我個人而言,我喜歡我剛剛展示的替代方案,因為它感覺更容易擴展,而且 IMO 感覺更容易在更清晰的意義上分離邏輯。 N.netheless,你做你,這兩種選擇都非常好,並提供自己的優點和缺點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.