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 fromcheckClick(){}.bind(this)
, which meansremoveEventListener()
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 examplecheckClick.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
2 Answers
Reset to default 4The 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.