Javascript 与es6类和jquery的绑定
在处理一个项目时,我注意到,Javascript 与es6类和jquery的绑定,javascript,jquery,ecmascript-6,Javascript,Jquery,Ecmascript 6,在处理一个项目时,我注意到,这个类内方法在通过jquery调用访问时并没有真正附加到实例,甚至也没有附加到类。相反,我看到的是窗口全局,这是不对的 因此,有多种方法可以为您自动绑定。。我试过几次,但都没成功。发生了什么事 以下是错误: Uncaught TypeError: this.chooseAtRandom is not a function at move (pen.js:83) move @ pen.js:83 pen.js:102 Uncaught TypeError: Ca
这个
类内方法在通过jquery调用访问时并没有真正附加到实例,甚至也没有附加到类。相反,我看到的是窗口
全局,这是不对的
因此,有多种方法可以为您自动绑定。。我试过几次,但都没成功。发生了什么事
以下是错误:
Uncaught TypeError: this.chooseAtRandom is not a function
at move (pen.js:83)
move @ pen.js:83
pen.js:102 Uncaught TypeError: Cannot read property 'push' of undefined
at UIController.animate (pen.js:102)
at HTMLDivElement.<anonymous> (pen.js:131)
at HTMLDivElement.dispatch (jquery.min.js:3)
at HTMLDivElement.q.handle (jquery.min.js:3)
animate @ pen.js:102
(anonymous) @ pen.js:131
dispatch @ jquery.min.js:3
q.handle @ jquery.min.js:3
pen.js:83 Uncaught TypeError: this.chooseAtRandom is not a function
at move (pen.js:83)
注意这里的Binder.getAllMethods
调用。如果我把它改成this.getAllMethods,我也会遇到一个问题。我想知道codepen是不是把它弄坏了
下面是我在使用它:
class SimonAudio {
constructor() {
this.soundsrcs = [
'https://s3.amazonaws.com/freecodecamp/simonSound1.mp3',
'https://s3.amazonaws.com/freecodecamp/simonSound2.mp3',
'https://s3.amazonaws.com/freecodecamp/simonSound3.mp3',
'https://s3.amazonaws.com/freecodecamp/simonSound4.mp3'
]
this.players = this.soundsrcs.map(s => {
let a = document.createElement('audio');
a.setAttribute('src', s)
return a
})
this.uiMap = {
red: 0,
green: 1,
amarillo: 2,
blue: 3
}
Binder.bind(this, SimonAudio)
}
play(uiId) {
this.players[this.uiMap[uiId]].play()
}
}
class Game {
constructor(UI) {
this.UI = UI
this.uiMap = {
red: 0,
green: 1,
amarillo: 2,
blue: 3
};
this.dexUi = ['red', 'green', 'amarillo', 'blue']
this.states = ['SHOWINGCHALLENGE', 'LISTENING']
this.audio = new SimonAudio()
this.moves = []
this.gameStack = []
this.inGame = false
Binder.bind(this, Game)
}
start() {
this.inGame = true
this.gameStack.push(setTimeout(this.move, parseInt((Math.random() + 1) * 1000)))
}
restart() {
this.moves = []
this.gameStack.forEach(a => {
clearTimeout(a)
})
this.gameStack = []
this.inGame = false
}
playMoves() {
let elf = this.UI
this.moves.forEach(m =>
this.gameStack.push(
setTimeout(function() {
elf.animate(m)
}, parseInt((Math.random() + 1) * 500)))
)
}
move() {
let move = this.chooseAtRandom()
this.moves.push(move)
this.playMoves()
}
chooseAtRandom() {
return this.dexUi[parseInt(Math.random() * 4)]
}
}
class UIController {
contructor() {
this.animation_stack = []
Binder.bind(this, UIController)
}
clear() {
this.animation_stack.forEach(a => clearTimeout(a))
this.animation_stack = []
}
animate(uiId) {
$(`#${uiId}`).addClass('highlight')
this.animation_stack.push(setTimeout(function() {
$(`#${uiId}`).removeClass('highlight')
}, 333))
}
}
然后,jquery将其放大:
$(function() {
let UI = new UIController()
let Simon = new Game(UI)
$('#strict').click(function() {
$(this).toggleClass('toggled')
})
$('#restart').click(function() {
$('.controls .button').removeClass('disabled toggled')
$('.game-buttons div').addClass('disabled')
Simon.restart()
})
$('#start').click(function() {
if (Game.inGame)
return
$('.game-buttons > div').addClass('hvr-radial-out')
$(this).addClass('toggled')
$('#strict').addClass('disabled')
$('.game-buttons div').removeClass('disabled')
Simon.start()
})
$('.game-buttons div').addClass('disabled')
.click(function() {
if ($(this).hasClass('disabled'))
return
let id = $(this).attr('id')
UI.animate(id)
Simon.audio.play(id)
})
})
据我所知,绑定通常用于将一个函数或多个函数绑定到一个对象 例如,使用JS的绑定:
this.start.bind(this);
或使用lodash的bind/bindAll:
_.bind(this.start, this);
_.bindAll(this, ['start', 'restart']);
在这些情况下,“this”指的是游戏类的一个实例。我相信这将确保绑定方法总是在游戏实例的上下文中被调用
您的方法似乎不太符合这种用法
我建议使用lodash bind/bindAll实现,而不是尝试自己实现
资源
move() {
let move = this.chooseAtRandom()
this.moves.push(move)
this.playMoves()
}
好的,就在这里,当函数实际启动时,您失去了希望保留的上下文。我们可以通过几种方式轻松地重写它。但在我开始复制/粘贴代码中另一个非常糟糕的部分之前,我必须先修复它
// parseInt is for converting strings to numbers
// Math.random() gives you a number so you don't need to parse it
// change this
parseInt((Math.random() + 1) * 1000)
// to this
(Math.random() + 1) * 1000
好的,现在让我们修复函数上下文
// Option 1: use Function.prototype.bind
this.gameStack.push(setTimeout(this.move.bind(this), (Math.random() + 1) * 1000))
// Option 2: use a sexy ES6 arrow function
this.gameStack.push(setTimeout(() => this.move(), (Math.random() + 1) * 1000))
好的,现在让我们检查是否使用正确的上下文调用了start
$('#start').click(function() {
if (Game.inGame)
return
$('.game-buttons > div').addClass('hvr-radial-out')
$(this).addClass('toggled')
$('#strict').addClass('disabled')
$('.game-buttons div').removeClass('disabled')
Simon.start()
})
$(“#开始”)。单击(函数(){
如果(Game.inGame)
返回
$('.game buttons>div').addClass('hvr-radial-out'))
$(this.addClass('toggled'))
$('#strict').addClass('disabled'))
$('.game buttons div')。removeClass('已禁用')
Simon.start()
})
好的!start
函数中的this
将设置为Game
的Simon
实例。我无法运行您的其余代码,因此我不知道是否还有其他问题,但这应该可以解决此问题。chooseAtRandom
不是您以前看到的函数错误
好。它似乎非常接近于boundGetX
示例。。它有什么显著的不同?var boundGetX=retrieveX.bind(模块)代码>--在boundGetX示例中,对象被绑定到函数(retrieveX)Binder.bind(这个,游戏)
——在您的示例中,您试图将对象绑定到类(Binder)。很抱歉,我没有正确查看您的Binder代码。我想我可能知道你现在想做什么了。不,谢谢,但是你没有正确阅读代码。我正在绑定类方法<代码>绑定。绑定是一个自定义方法,它为对象的每个方法或属性处理绑定,对于给定的任何类,我都是从中获得的,它可能不正确,但看起来差不多正确。。我不知道你是否需要一个自定义绑定实现,但我想我用lodash的bind和bindAll方法替换了你的自定义代码,从而使游戏正常运行。“开始”和“重新启动”按钮似乎仍在工作:。在我看来,对于像bind这样的东西,使用本机或第三方方法通常比尝试自己的方法要好,这并不是说尝试有什么错。这很好,真的很好,谢谢。我刚刚发现这是在和另一个到目前为止回答的人谈话。但是从您寻址的对moves()
的调用向下两行是对playMoves
的调用,该调用引用内部UIController
。这也触发了setTimeout调用,但以类似的方式更改它们并不能解决问题:`this.gameStack.push(setTimeout(function(){elf.animate(m).bind(elf)},parseInt((Math.random()+1)*500)))`你有没有遵循一些指导来做这件事,或者你是自己来做这些课程的?自动装订非常混乱,可能是我看不出的其他问题的原因。我没有遵循指南,不。我不明白你为什么认为这很混乱。我确实是从别人那里得到的。。在任何情况下,我都不喜欢它,特别是因为它没有;似乎无法像这样解析嵌套类。总之,另一个人找到了一个有效的解决办法。配合lodash@robertotom首先,您实现的Binder
与该要点不同。gist为getAllMethods
和bind
提供了静态类方法,而您的gist是通过实例方法实现的。第二,我觉得自动绑定适用于那些不太了解动态函数上下文的人;ie想象起来很可怕,为了编写一个简单的游戏,必须将每个类中的每个方法绑定到一个已知的上下文。不管它值多少钱,我已经有将近两年没有在生产代码中使用Function.prototype.bind
。只是没那么重要。。。。如果你如此依赖它,我认为人们对JavaScript的工作原理有一个根本性的误解。第三,这是我见过的最伤脑筋的命题逻辑表达:!(!(函数的方法实例)| |方法===cls)代码>–可以用更直接的方式表示为函数和方法的methodinstanceof Function&&method!==cls代码>–另请参见:
// Option 1: use Function.prototype.bind
this.gameStack.push(setTimeout(this.move.bind(this), (Math.random() + 1) * 1000))
// Option 2: use a sexy ES6 arrow function
this.gameStack.push(setTimeout(() => this.move(), (Math.random() + 1) * 1000))
$('#start').click(function() {
if (Game.inGame)
return
$('.game-buttons > div').addClass('hvr-radial-out')
$(this).addClass('toggled')
$('#strict').addClass('disabled')
$('.game-buttons div').removeClass('disabled')
Simon.start()
})