Javascript 将html事件绑定到构造函数中控制器类的实例

Javascript 将html事件绑定到构造函数中控制器类的实例,javascript,jquery,Javascript,Jquery,抱歉,关于将处理程序绑定到实例,可能有一点noobjs问题 我正在创建一个控制器实例,其中包含一些数据,这些数据随后将用于处理传入事件(实际用例是使用不同的ajax URL组合复杂的d3处理程序,并在其中组合执行实际树更新的函数) RequireJS和jquery都涉及其中,但我怀疑我的问题更多地与我的特定绑定代码有关。我想我可以放弃使用“this”,因为我每页只有一个控制器,可以是全局控制器。但这感觉应该是可行的,只要我知道怎么做 这就是我如何从构造函数内部将控制器绑定到其目标上的方法(在构造

抱歉,关于将处理程序绑定到实例,可能有一点noobjs问题

我正在创建一个控制器实例,其中包含一些数据,这些数据随后将用于处理传入事件(实际用例是使用不同的ajax URL组合复杂的d3处理程序,并在其中组合执行实际树更新的函数)

RequireJS和jquery都涉及其中,但我怀疑我的问题更多地与我的特定绑定代码有关。我想我可以放弃使用“this”,因为我每页只有一个控制器,可以是全局控制器。但这感觉应该是可行的,只要我知道怎么做

这就是我如何从构造函数内部将控制器绑定到其目标上的方法(在构造函数外部执行此操作似乎有效):

出了什么问题?

当我单击按钮时,handleClick中的“this”指的是html按钮,而不是控制器实例

如果我直接调用控制器实例方法,“this”是正确的

我已尝试调用或创建包装器函数,如中所示

My button click一直将“this”视为按钮,而不是控制器:

输出

global var controller:BtnMgr.I am a button
this:[object HTMLButtonElement],type:
e:[object Object],type:Object
BtnMgr.handleClick:this.msg:undefined
简化版:

HTML

page4.html

<!DOCTYPE html>
<html>
<head>
    <title>Page 4</title>
    <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.15/require.min.js"></script>
    <script type="text/javascript">
    requirejs.config({
        baseUrl: '.',
        paths: {
            "jquery": "//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min"
        }
    });
    var controller;
    require(["main4"], function(BtnMgr) {
        controller = new BtnMgr("I am a button", "btn_click");
        //this simulated call works - 'this' refers to the BtnMgr instance
        controller.handleClick("dummy_btn");
    });
    </script>
</head>
<body>
    <button id="btn_click">click me!</button>
</body>
</html>

绑定onClick时请尝试以下操作:

function BtnMgr(msg, tgt_id) {
    this.msg = msg;
    this.tgt_id = tgt_id;
    var selector = "#" + tgt_id;
    $(selector).on("click", $.proxy(this.handleClick, this));
}
这将确保回调中的“this”变量是您的类,而不是clickevent。 您可以在此处阅读有关jQuery代理的更多信息:

您可以(几乎)实现您想要的:

$(selector).on("click", this.handleClick.bind(this));
将是BtnMgr的实例,
e.target
将一如既往地作为按钮

然而,这将与传统背道而驰,并使任何试图理解您的代码的人感到困惑,包括您自己。在单击处理程序中,
这个
应该总是引用单击的元素,这是很自然的

如果您真的必须从处理程序获得一个指向附加单击的BtnMgr实例的引用,那么我可能会选择这样的“e-augmentation”:

function BtnMgr(msg, tgt_id) {
    var that = this;
    this.msg = msg;
    this.tgt_id = tgt_id;
    var selector = "#" + tgt_id;
    $(selector).on("click", function(e) {
        e.clickAttacher = that;
        that.handleClick(e);
    });
}

BtnMgr.prototype.toString = function(){
    return "BtnMgr." + this.msg;
};

BtnMgr.prototype.handleClick = function(e) {
    console.log("click attacher was instance of : " + e.clickAttacher.constructor.name); // BtnMgr
    console.log("button id: " +  e.target.id); // xxx
    console.log("msg: " + e.clickAttacher.msg); // Hello World!
};

var b = new BtnMgr('Hello World!', 'xxx');


这样做之后,您必须问这样定义
handleClick
是否真的值得。当然,如果它是一个怪物函数,那么是的,用
BtnMgr.prototype….
定义它,但是如果它很小,那么就在构造函数中定义它,并直接利用
在作用域链中的作用(就像上面的增强函数一样)。

让我检查一下,但是是的,我认为代理是我想要的。我在别处遇到了另一个相同类型的错误——糟糕的“this”。关于“说Javascript”,作者说,当调用存储在变量中的方法时,需要重复实例变量。我怀疑$的代理会这样做,还有更多。在Python上,一旦您存储了对实例方法的引用,它就会从那时起知道该实例,因此我从JS中假设了同样的情况。请注意,这也花了我很长时间才弄清楚。是的,代理方法创建了一个带有“this”的变量,然后使用存储的对“this”的引用对该方法调用apply。如果你想更多地了解它的工作原理,你可以在谷歌上搜索“js应用”。丹和你都有正确的想法,那就是使用$.proxy或bind来强制“this”中的内容。bind似乎更适合现代JS,所以我选择它。我不想让“this”引用按钮的原因是,在我的实际使用中,这只是一个manager对象的事件。经理通过requirejs加载了许多松散耦合的模块:一个带有样板文件的通用d3树模块。不同的页面有不同的d3模块来添加要调用的节点和ajax URL。管理器“this”协调所有处理,因此事件的起源无关紧要。
function BtnMgr(msg, tgt_id) {
    this.msg = msg;
    this.tgt_id = tgt_id;
    var selector = "#" + tgt_id;
    $(selector).on("click", $.proxy(this.handleClick, this));
}
$(selector).on("click", this.handleClick.bind(this));
function BtnMgr(msg, tgt_id) {
    var that = this;
    this.msg = msg;
    this.tgt_id = tgt_id;
    var selector = "#" + tgt_id;
    $(selector).on("click", function(e) {
        e.clickAttacher = that;
        that.handleClick(e);
    });
}

BtnMgr.prototype.toString = function(){
    return "BtnMgr." + this.msg;
};

BtnMgr.prototype.handleClick = function(e) {
    console.log("click attacher was instance of : " + e.clickAttacher.constructor.name); // BtnMgr
    console.log("button id: " +  e.target.id); // xxx
    console.log("msg: " + e.clickAttacher.msg); // Hello World!
};

var b = new BtnMgr('Hello World!', 'xxx');