[英]Recursive Function in React.JS Component class
我有一個使用 React 的項目的問題。 這是一個井字游戲,我正在嘗試實現計算機播放器。
當人類玩家點擊一個方塊(Field 組件)時,這會觸發 Board 組件中的updateField()函數。 它還調用computerMove()函數,該函數又調用minimax()函數。
minimax 函數是遞歸定義的。 但是,當代碼執行到達調用minimax(possibleGame)的行時,我收到以下錯誤消息。
[ERROR] react-dom Uncaught TypeError: Cannot read property 'minimax' of undefined
顯然該功能未知,我不明白,因為我將其綁定到 Board 范圍。
class Field extends React.Component{
render(){
return(
<button className='field' onClick={this.props.clickFunc}>{this.props.value}</button>
);
}
}
class Board extends React.Component{
constructor(){
super();
this.state = {
fields: Array(9).fill(null),
};
this.minimax = this.minimax.bind(this);
this.updateField = this.updateField.bind(this);
this.computerMove = this.computerMove.bind(this);
}
updateField(id){
const fields = this.state.fields.slice();
// only proceed if field hasn't been taken yet
if (fields[id] == null && this.props.winner == null){
fields[id] = this.props.playerSymbol;
this.setState({fields: fields});
this.computerMove(fields);
}
}
// check if somebody won the game
checkWinner(squares){
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a];
}
}
return null;
}
computerMove(fields){
var computerSymbol = (this.props.playerSymbol == "X" ? "O" : "X");
var game = {fields: fields,turn:computerSymbol};
var result = this.minimax(game);
var newBoard = fields.slice();
newBoard[result[1]] = computerSymbol;
this.setState({fields: newBoard});
}
score(game){
// check for winner
var result = this.checkWinner(game.fields);
if (result !== null){
if (result == this.props.playerSymbol){
return -10;
} else{
return 10;
}
}else{
return 0;
}
}
minimax(game) {
var score = this.score(game);
if (score !== 0){
return score;
}
var scores = [];
var moves = [];
game.fields.forEach(function(value,index,arr){
if (value==null){
var newField = arr.slice();
newField[index] = game.turn;
var nextTurn = (game.turn == "X" ? "O" : "X");
var possibleGame = {fields: newField,turn:nextTurn};
var result = this.minimax(possibleGame);
scores.push(result[0]);
moves.push(index);
}
});
if (game.turn == this.props.playerSymbol){
var max_ind = scores.indexOf(Math.max(...scores));
return [scores[max_ind],moves[max_ind]];
} else{
var min_ind = scores.indexOf(Math.min(...scores));
return [scores[min_ind],moves[min_ind]];
}
}
render(){
var fields = this.state.fields;
// check if somebody won
const winner = this.checkWinner(fields);
if (winner){
this.props.declareWinner(winner);
}
return (
<div className="animated fadeInUp board-container">
<div className='row'>
<Field value={fields[0]} clickFunc={() => this.updateField(0)} />
<Field value={fields[1]} clickFunc={() => this.updateField(1)}/>
<Field value={fields[2]} clickFunc={() => this.updateField(2)}/>
</div>
<div className='row'>
<Field value={fields[3]} clickFunc={() => this.updateField(3)} />
<Field value={fields[4]} clickFunc={() => this.updateField(4)}/>
<Field value={fields[5]} clickFunc={() => this.updateField(5)}/>
</div>
<div className='row'>
<Field value={fields[6]} clickFunc={() => this.updateField(6)}/>
<Field value={fields[7]} clickFunc={() => this.updateField(7)}/>
<Field value={fields[8]} clickFunc={() => this.updateField(8)}/>
</div>
</div>
)
}
}
整個代碼可以在這里測試: https : //codepen.io/miga89/pen/pPqmra
我也試圖想出一個 MWE ( https://codepen.io/miga89/pen/XRQBjP ) 但是,這個例子出於某種原因有效。
感謝您的幫助!
this
的值取決於調用函數的方式和位置。
在大多數情況下,
this
的值取決於函數的調用方式。 不能在執行時通過賦值來設置,而且每次調用函數的時候可能都不一樣。 ES5 引入了 bind 方法來設置函數 this 的值,不管它是如何調用的,ES2015 引入了箭頭函數,其 this 是詞法范圍的(它被設置為封閉執行上下文的 this 值)。 https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/this
您需要顯式綁定this
以在函數內一致使用。
game.fields.forEach(function(value,index,arr){
if (value==null){
var newField = arr.slice();
newField[index] = game.turn;
var nextTurn = (game.turn == "X" ? "O" : "X");
var possibleGame = {fields: newField,turn:nextTurn};
var result = this.minimax(possibleGame);
scores.push(result[0]);
moves.push(index);
}
}.bind(this));
或者,使用箭頭函數:
game.fields.forEach((value,index,arr) => {
if (value==null){
var newField = arr.slice();
newField[index] = game.turn;
var nextTurn = (game.turn == "X" ? "O" : "X");
var possibleGame = {fields: newField,turn:nextTurn};
var result = this.minimax(possibleGame);
scores.push(result[0]);
moves.push(index);
}
});
箭頭函數表達式的語法比函數表達式更短,並且不綁定自己的 this、arguments、super 或 new.target。 這些函數表達式最適合非方法函數,它們不能用作構造函數。 https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions
維護遞歸規則:假設我們有一個父子樹,那么在下面你會找到一個例子
在構造函數中:
this.checkSlug = this.checkSlug.bind(this);
this.onViewToBar = this.onViewToBar.bind(this);
您的遞歸函數示例:
checkSlug = (slug, parent) => {
for (let i = 0; i < parent.length; i++) {
if (parent[i].children && parent[i].slug !== slug) {
const value = this.checkSlug(slug, parent[i].children);
if (value){
return value;
}
} else {
if (parent[i].slug === slug) {
return parent[i];
}
}
}
}
現在我的來電功能
onViewToBar({ slug }) {
this.setState({ slug: slug });
const { cursor, data } = this.state;
let node =this.checkSlug(slug, data);
}
```
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.