Javascript范围addEventListener和this [英] Javascript scope addEventListener and this

查看:216
本文介绍了Javascript范围addEventListener和this的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一名C#开发人员,正在尝试使用JavaScript,我正试图绕过范围:)

I am a C# developer experimenting with JavaScript and I'm trying to get my head around the scope :)

我有以下代码,其中包含 addEventListener 我想在其中使用我的对象中的字段:

I have the following code which contains an addEventListener in which I want to use a field from my object:

(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数组,但是我知道我无法访问是通过使用这,因为这是该上下文中的窗口(正确吗?)。
如果我将其更改为

I would like to use the keys array in my hander, but understand that I cannot access is by using this, because this is the window in that context (correct?). If I change it to

app.util.keyboard.keys[args.keyCode] = true;

它有效,但我不确定这是解决问题的好办法。

it works, but I'm not sure that's a good way to fix it.

我找到了这个问题,这看起来很相似,但我不知道我怎么能适应我的例子。

I found this question, which seems rather similar, but Im not sure how I can fit it into my example.

感谢您的帮助!

推荐答案

一些事情:


  • 大多数人会建议像 var self = this 因为它快速而简单。

但是 var self = this 不会将视图对象完全与视图逻辑分开,后者来自更正式的C#背景并查看您的代码,听起来像是某种东西你想做什么。

But var self = this does not separate the view object entirely from the view logic, which coming from a more formal C# background and looking at your code, sounds like something you want to do.

为了让回调只在事件触发时执行,将处理程序包装在一个函数中,以便立即进行评估,但只在 keydown 时执行事件触发(参见下面的代码)。

In order to have the callback execute only when the event fires, wrap the handler in a function, so that it's evaluated right away, but only executed when and if a keydown event fires (see the code below).

了解JS中的范围:无论执行上下文是什么,它也是当前范围。您的侦听器已添加到 Keyboard.prototype 上的方法(名为 listen )中,但 keydown 事件实际上是在窗口上触发的 - 处理程序在不同于其定义的上下文中执行;它正在调用它的上下文中执行,在这种情况下, window ,所以它的范围是 window 除非你在定义时,通过 bind 应用将其绑定到另一个对象。

Understanding scope in JS: Whatever the execution context is, is also the current scope. Your listener was added in a method (called listen) on Keyboard.prototype, but the keydown event is actually fired on window -- the handler is executing in a different context than where it was defined; it's executing within the context of what is invoking it, in this case, window, so it's scoped to window unless you bind it to another object via bind or apply when it's defined.

在您的代码中,窗口是用户的视图与...交互,键盘是该视图的控制器。在MVC模式中,就像您在C#/ .NET中可能习惯的那样,视图不会告诉自己在事情发生时该做什么,控制器告诉视图要做什么。所以,如果你要像许多人一样使用 var self = this 来为控制器分配一个引用,那么视图将自行管理 - 但仅限于特定的处理程序对于 keydown 事件。这是不一致的,并且在大型项目中变得难以管理。

In your code, window is the view a user's interacting with, and Keyboard is that view's controller. In MVC patterns like what you're probably used to in C#/.NET, views don't tell themselves what to do when things happen, controllers tell views what to do. So, if you were to assign a reference to the controller by using var self = this like so many do, the view would be managing itself -- but only for that specific handler for keydown events. This is inconsistent and would become hard to manage in a large project.

解决方案:

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 准备好了):

The best solution (until ES6 class is ready):

// 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();



查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆