admin 管理员组

文章数量: 1086019

When I bind a function with the parent this passed in thisArg, I can't unbind the same named function expression, but without it I can unbind the function itself. Why is that?

This works:

choicesList.addEventListener("click", function() {

    const self= this;

    document.addEventListener("click", function checkClick(e) {

        if (!e) e = event;
        if (!self.contains(e.target)) {

            document.removeEventListener("click", checkClick);
        }
    }, false);
});

This doesn't:

choicesList.addEventListener("click", function() {

    document.addEventListener("click", function checkClick(e) {

        if (!e) e = event;
        if (!this.contains(e.target)) {
            document.removeEventListener("click", checkClick);
        }
    }.bind(this), false);
});

When I bind a function with the parent this passed in thisArg, I can't unbind the same named function expression, but without it I can unbind the function itself. Why is that?

This works:

choicesList.addEventListener("click", function() {

    const self= this;

    document.addEventListener("click", function checkClick(e) {

        if (!e) e = event;
        if (!self.contains(e.target)) {

            document.removeEventListener("click", checkClick);
        }
    }, false);
});

This doesn't:

choicesList.addEventListener("click", function() {

    document.addEventListener("click", function checkClick(e) {

        if (!e) e = event;
        if (!this.contains(e.target)) {
            document.removeEventListener("click", checkClick);
        }
    }.bind(this), false);
});
Share Improve this question edited Nov 27, 2018 at 2:29 Dacre Denny 30.4k5 gold badges51 silver badges66 bronze badges asked Nov 27, 2018 at 2:10 Rick StanleyRick Stanley 8502 gold badges13 silver badges25 bronze badges 3
  • I do can unbind ????? – Scott Marcus Commented Nov 27, 2018 at 2:12
  • it's because the declared checkClick function !== the function resulting from checkClick(){}.bind(this), which means removeEventListener() fails to find a match – Dacre Denny Commented Nov 27, 2018 at 2:13
  • 1 note that Function.bind() !== Function.bind(). Every call to .bind creates another object or function (your second example checkClick.bind(this) !== checkClick). In order to remove an event listener you MUST pass in the same object (function) and options used to create the event listener. – Jay Harris Commented Nov 27, 2018 at 2:26
Add a ment  | 

2 Answers 2

Reset to default 4

The reason for this is issue is that calling bind() on a function returns a new instance of that function:

function someHandler() {
  alert('hi');
}

const someHandlerBinded = someHandler.bind(document);


// Returns false, seeing as these are different instances of the function
console.log( someHandlerBinded === someHandler );

By setting an event handler directly, via the result of bind() as you are in your second block of code, this causes a new instance of that function handler to be passed to addEventListener(). This in turn means that the subsequent attempt to removing this handler on line:

document.removeEventListener("click", checkClick);

will fail, seeing that the the defined function checkClick is not the same as the actual handler function used for that click event (ie the new function instance returned from function checkClick(){ ... }.bind())

One way to resolve this might be the following:

choicesList.addEventListener("click", function() {

    // Declare the bound version of the click handler
    const boundClickHandler = function checkClick(e) {

        if (!e) e = event;

        if (!this.contains(e.target)) {

            // Removing the result of bind, rather than the declared 
            // checkClick handler
            document.removeEventListener("click", boundClickHandler);
        }
    }.bind(this)

    // Adding the result of bind as you currently are doing
    document.addEventListener("click", boundClickHandler, false);
});

It's because this is in a function that is nested within another function and the nested function doesn't have the same invocation context as the outer one. The first one works because you are caching the object that the outermost this is referencing and you are then able to correctly reference it in the inner function.

You can read more about the volatility of this here.

本文标签: Javascript Bindunbind function behaviorStack Overflow