javascript - 动画 DFS - 在 Javascript 对象中使用 setInterval 和 this 的问题
问题描述
我在 HTML 中有一个按钮网格,我想通过在第一次访问按钮时更改按钮的颜色,然后在完成访问时更改按钮的颜色,来为深度优先搜索设置动画。我正在使用 Javascript 对象来处理所有逻辑,并使用递归 DFS 方法来构建像[[animation_function, grid_coordinates], ... ]
. 然后我使用该setInterval
函数遍历整个队列。
DFSGrid
问题是对象在运行时似乎消失了DFSGrid.animate()
?如果我console.log(this)
在 内DFSGrid.animate()
,它似乎this
是指 Window 对象?但this
在所有其他方法中都可以正常工作。
我是网络东西的新手(真的是 Javascript),所以我非常困惑。我尝试了各种不同的东西,但我总是遇到一些问题,this
当动画应该运行时,或者那个 (lol) 是未定义的。
我究竟做错了什么?
class DFSGrid {
constructor(dfsGridElement) {
this.dfsGridElement = dfsGridElement
this.dirs = [[0, 1], [-1, 0], [0, -1], [1, 0]]
this.visited = new Set()
this.visited.add('00')
this.queue = []
this.idx = 0
}
dfs(i, j) {
if (i > 5 || j > 3) {
return
}
const coords = i.toString() + j.toString()
this.queue.push([this.visit, coords])
for (let d of this.dirs) {
let [ni, nj] = [i + d[0], j + d[1]]
let nextCoords = ni.toString() + nj.toString()
if (0 <= ni && ni <= 5 && 0 <= nj && nj <= 3 && (!this.visited.has(nextCoords))) {
this.visited.add(nextCoords)
this.dfs(ni, nj)
}
}
this.queue.push([this.finish, coords])
}
visit(coords) {
// The grid of buttons has class selectors like:
// <button class="c00">00</button>
let cell = this.dfsGridElement.querySelector('.c' + coords)
cell.style.backgroundColor = 'red'
}
finish(coords) {
let cell = this.dfsGridElement.querySelector('.c' + coords)
cell.style.backgroundColor = 'black'
}
animate() {
console.log(this)
let idx = this.idx
if (idx > this.queue.length) {
return
}
let [func, coords] = [this.queue[idx][0], this.queue[idx][1]]
func(coords)
this.idx += 1
}
}
const dfsGridElement = document.querySelector('.dfs-grid')
const dfsGrid = new DFSGrid(dfsGridElement)
dfsGrid.dfs(0,0)
setInterval(dfsGrid.animate, 2000)
* {
box-sizing: border-box;
font-name: Gothic Rounded, sans serif;
}
.app-content {
margin: 0px;
padding: 0px;
background: linear-gradient(to right, #00AAFF, #00FFA6);
color: gray;
height: 100%;
}
.dfs-grid {
display: grid;
min-height: 100vh;
justify-content: center;
align-content: center;
grid-template-columns: repeat(4, 100px);
grid-template-rows: minmax(120px, auto) repeat(5, 100px);
}
.dfs-grid button {
cursor: pointer;
font-size: 2rem;
outline: none;
border: 1px solid white;
background-color: rgba(255, 255, 255, 0.75);
}
.dfs-grid button:hover {
background-color: rgba(255, 255, 255, 0.9);
}
<div class="app-content">
<div class="dfs-grid">
<button class="cell c00">00</button>
<button class="cell c01">01</button>
<button class="cell c02">02</button>
<button class="cell c03">03</button>
<button class="cell c10">10</button>
<button class="cell c11">11</button>
<button class="cell c12">12</button>
<button class="cell c13">13</button>
<button class="cell c20">20</button>
<button class="cell c21">21</button>
<button class="cell c22">22</button>
<button class="cell c23">23</button>
<button class="cell c30">30</button>
<button class="cell c31">31</button>
<button class="cell c32">32</button>
<button class="cell c33">33</button>
<button class="cell c40">40</button>
<button class="cell c41">41</button>
<button class="cell c42">42</button>
<button class="cell c43">43</button>
<button class="cell c50">50</button>
<button class="cell c51">51</button>
<button class="cell c52">52</button>
<button class="cell c53">53</button>
</div>
</div>
解决方案
原来我上面遇到的this
问题在这里被描述为“问题”:https ://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval
使用 时setInterval
,this
被调用函数的关键字将是window
对象。解决这个问题的一种方法是使用Function.prototype.bind
。
const startDFSAnimation = dfsGrid.animate.bind(dfsGrid)
startDFSAnimation()
上面将运行该dfsGrid.animate
函数的新版本,但我们确保this
它将引用dfsGrid
它运行的时间。
编辑:正如@Caleb Miller 指出的那样,这也可以通过在我认为更好的类的构造函数中绑定来解决。
class DFSGrid {
constructor(dfsGridElement) {
// Do this for all class methods that are used by
// setTimeout or setInterval functions
this.animate = this.animate.bind(this)
this.visit = this.visit.bind(this)
this.finish = this.finish.bind(this)
}
推荐阅读
- mysql - Wordpress Docker 容器无法连接到数据库
- python - 如何使用 Python 在不同大小的列表列表中查找重复项并创建另一个包含分组元素的列表?
- c# - TestCaseSource 产生一个 IDE0052 警告。如何避免?
- django - 我真的找不到我的问题..但我的问题是我的元组中有重复的东西
- php - 如何在 PHP 中将文件从表单上传到 API?
- python-requests - 最近使用 Overpass API 的 ConnectionErrors
- amazon-web-services - 不可预测的 Cloudfront 502 错误
- python - Aria2c 标头问题
- c# - 如何使用 GetCurrentInputMessageSource() 区分鼠标和触摸板事件?
- ubuntu - Selenium ChromeDriver 在 AWS EC2 Ubuntu 机器中抛出错误“驱动程序可执行文件必须存在:/ usr ...”