Skip to content

About the author of Daydream Drift

Tomasz Niezgoda (LinkedIn/tomaszniezgoda & GitHub/tniezg) is the author of this blog. It contains original content written with care.

Please link back to this website when referencing any of the materials.

Author:

Using .bind() In JavaScript Is A Memory Leak Risk. Here's Why.

Published
// ...
function listener(event){
	// ...
};

$(window).on(listener).bind(this);
// ...

Using bind on a function will return a new function. So, for example, it's easy to register a bound function to accept events and handle them within the right context. But deregistering it may produce unexpected results. Consider the following:

function p(){};
let w = p === p.bind(document);

w will return false, because bind returned a copy of the original function. What happens a lot in JavaScript is adding event listeners to code that will run when something happens on a website. The typical context for the bound function when it's called is null/window, meaning the function's original scope is lost. bind remedies that, except it makes cleaning up tougher and more error prone also.

The publisher/subscriber pattern in javascript is usually implemented by tracking references to functions that listen for events. Since p and p.bind(document) have different references due to being effectively different functions, doing publisher.off(p) or similar to stop listening for a publisher's events won't work. To make matters worse, it may lead to memory leaks.

One possible solution is to reference the bound function instead of the original. It's not very clean but works. Another is leveraging scope and using a scoped variable created outside the function but within its scope tree (usually let self = this), to reference the right scope. Another is to use ES6 arrow functions. Their current implementation is rather slow but they're concise and automatically use the inherited scope of where they were created which is usually what's needed. If some tooling is being built or even a whole framework, it might be a good idea to automatically assign the expected scope. A while ago, older versions of Facebook's React would reassing functions' scopes to always reference the parent component. Thanks to this approach, bind was rarely needed and user interaction handlers were easier to implement. But Facebook did eventually remove this behavior in favour of arrow functions, which says something about their usefulness. One last approach that I rarely use is utilizing the context parameter provided by some JavaScript tools. Some native code and JavaScript libraries allow an optional context parameter, so they can bind the function themselves. Obviously, this pressures programmers to do more work which can be avoided with arrow functions and other solutions, so I'd expect this trend to fade away.