Why does removeeventlistener not work in this obje

2020-02-11 09:01发布

I am working on a game and I would like to abstract my ui, and bind unbind events based on various game states. But I can't figure out why this event is not being removed. It seems the scope is correct in the handler.

fiddle

relevant (stripped down) js:

var controls = {
    game : {
        el : null,
        cb : null,

        bind : function(el, cb) {
            this.el = el;
            this.cb = cb;
            this.el.addEventListener('click', this.handler.bind(this), true);
        },

        unbind : function() {
            console.log('unbind');
            this.el.removeEventListener('click', this.handler, true);
        },

        handler : function() {
            this.cb();
            this.unbind();
        }
    }
};

var manager = {
    init : function() {
        var c = document.getElementById('c');
        controls.game.bind(c, this.action.bind(this));
    },

    action : function() {
        console.log('c clicked');
    }
};
manager.init();

And yet if I remove the event this way it works:

(...)

bind : function(el, cb) {
    this.el = el;
    this.cb = cb;
    var self = this;
    this.el.addEventListener('click', function() {
        self.cb();
        self.el.removeEventListener('click', arguments.callee, true);
    }, true);
}

(...)

thanks

2条回答
霸刀☆藐视天下
2楼-- · 2020-02-11 09:24

.bind returns a new function. this.handler.bind(this) !== this.handler! You would have to store a reference to the new function somehow.

For example, storing a reference in a variable and using a closure:

var handler = this.handler.bind(this);
this.el.addEventListener('click', handler, true);

this.unbind = function() {
    this.el.removeEventListener('click', handler, true);
}

As alternative to arguments.callee, you could also give the function a name:

this.el.addEventListener('click', function handler() {
    self.cb();
    self.el.removeEventListener('click', handler, true);
}, true);
查看更多
The star\"
3楼-- · 2020-02-11 09:42

Instead of playing with binding which also requires more memory I'd recommend using the following:

var song = {
    handleEvent: function (event) {
      switch (event.type) {
        case: "click":
          console.log(this.name);
          break;
      }
    },
    name: "Yesterday"
};

songNode.addEventListener("click", song);
songNode.click(); // prints "Yesterday" into console

You can use an object obj that has handleEvent property as a handler on any DOM object to catch its events and have event handler's context set to that object obj without the use of Function.prototype.bind.

That way you can also remove handlers, so

songNode.removeEventListener("click", song);
查看更多
登录 后发表回答