我是一名C#开发人员,正在尝试使用JavaScript,而我正试图让我的头脑在我的范围内:)
我有以下代码,其中包含addEventListener
,我想在其中使用对象中的字段:
(function(window) {
function Keyboard() {
this.keys = {};
}
Keyboard.prototype.handle_keydown = function(args) {
this.keys[args.keyCode] = true;
}
Keyboard.prototype.listen = function() {
window.addEventListener('keydown', this.handle_keydown);
}
app.util.keyboard = new Keyboard();
})(window);
我想在我的hander中使用keys数组,但是理解我无法访问是通过使用它,因为这是该上下文中的窗口(正确吗?)。 如果我将其更改为
app.util.keyboard.keys[args.keyCode] = true;
它有效,但我不确定这是解决问题的好方法。
我找到了this question,这看起来很相似,但我不确定如何将它融入我的例子中。
感谢您的帮助!
答案 0 :(得分:38)
一些事情:
大多数人会建议像var self = this
这样的东西,因为它快速而简单。
但var self = this
并未将视图对象与视图逻辑完全分开,后者来自更正式的C#背景并查看您的代码,听起来像你想要做的事情。
为了让回调只在事件触发时执行,将处理程序包装在一个函数中,以便立即对其进行评估,但仅在keydown
事件触发时执行(参见代码如下)。
了解JS中的范围:无论执行上下文是什么,也是当前范围。您的侦听器已添加到listen
上的方法(名为Keyboard.prototype
)中,但keydown
事件实际上是在window
上触发的 - 处理程序在不同的上下文中执行它被定义的地方;它正在调用它的上下文中执行,在本例中为window
,因此除非您通过window
或bind
将其绑定到另一个对象,否则它的作用域为apply
它被定义了。
在您的代码中,window
是用户与之交互的视图,Keyboard
是该视图的控制器。在MVC模式中,就像您在C#/ .NET中可能习惯的那样,视图不会告诉自己在事情发生时该做什么,控制器告诉视图要做什么。因此,如果您像许多人一样使用var self = this
来分配对控制器的引用,那么视图将自行管理 - 但仅针对keydown
事件的特定处理程序。这是不一致的,并且在大型项目中变得难以管理。
解决方案:
Keyboard.prototype.listen = function() {
window.addEventListener('keydown', function(e) {
this.handle_keydown(e);
}.bind(this), false);
}
更好的解决方案:
Keyboard.prototype.view = window;
Keyboard.prototype.listen = function() {
this.view.addEventListener('keydown', function(e) {
this.handle_keydown(e);
}.bind(this), false);
}
最佳解决方案(直到ES6 class
准备就绪):
// define
function addViewController(view) {
function ViewController() {
this.handle_keydown = function(args) {
// handle keydown events
};
this.listen = function() {
this.view.addEventListener('keydown', function(e) {
this.handle_keydown(e);
}.bind(this), false);
};
this.view = view;
return this;
}
return new ViewController(view);
}
// implement
var keyboard = addViewController(window);
keyboard.listen();
.bind()
与ECMAScript 5+兼容;如果您需要针对旧浏览器的解决方案,Mozilla已使用.bind()
和functions
发布了.call()
的绝佳替代方案:https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
编辑:以下是使用这种新的模块化解决方案的实例化keyboard
对象:
答案 1 :(得分:5)
Keyboard.prototype.listen = function() {
var self = this;
window.addEventListener('keydown', function(event) {
self.handle_keydown(event);
// self is your Keyboard object. You can refer to all your properties from this
});
}
此代码的工作原理:
this
变量的引用。 this
指向dom对象,而self
指向键盘对象。event
作为参数调用闭包,我们将其传递给键盘对象的成员函数。答案 2 :(得分:3)
怎么样
function Keyboard() {
this.keys = {};
var self = this;
this.handle_keydown = function(args) {
self.keys[args.keyCode] = true;
}
this.listen = function() {
window.addEventListener('keydown', this.handle_keydown);
}
}
app.util.keyboard = new Keyboard();