Understanding Polyfills in JavaScript (with a Custom bind() Example)

When working with JavaScript, especially in a browser environment, you’ll often encounter situations where a particular method or feature isn’t supported in all browsers. This is where polyfills come into play.
What is a Polyfill?
A polyfill is a piece of code that acts as a fallback for features that are not natively supported by certain browsers or JavaScript environments. It "fills in" the gap by implementing the missing functionality, ensuring consistent behavior across environments.
A Quick Recap of bind()
The bind()
function creates a new function with the this
keyword permanently set to the object you provide. It also lets you pass some arguments in advance.
Let's Start With an Example
let name = {
firstName: 'Jack',
lastName: 'Smith',
};
let printFullName = function(hometown, state, country) {
console.log(this.firstName + ' ' + this.lastName, 'from', hometown, state, country);
};
let printMyName = printFullName.bind(name, 'Hyderabad', 'Telangana');
printMyName('India'); // Output: Jack Smith from Hyderabad Telangana India
What’s happening here?
bind()
creates a new functionprintMyName
.It locks
this
to thename
object.It also pre-fills two arguments:
'Hyderabad'
and'Telangana'
.Later, we pass
'India'
when calling the function.
Want to dive deeper into
this
,call()
,apply()
, andbind()
in JavaScript?
Check out my detailed blog:
👉 Understandingthis
,bind()
,call()
, andapply()
in JavaScript
Now, Let’s Build Our Own bind()
– A Polyfill
To understand bind()
more deeply, let's implement our own version called myBind()
and handle various scenarios step by step.
Example:
let name = {
firstName: 'Jack',
lastName: 'Smith',
};
let printFullName = function() {
console.log(this.firstName + ' ' + this.lastName);
};
// custom bind function
// if we keep any method in the Function prototype, we can use it on any function
Function.prototype.myBind = function (...args) {
// Here args are used to get arguments passed to the myBind function
// inside the function, 'this' refers to the function we are calling myBind on.
let func = this; // In this example, 'this' refers to printFullName
let obj = args[0] // First argument is the object we want to point to
// bind should return a new function
return function () {
func.apply(obj);
};
};
let printMyName = printFullName.myBind(name);
printMyName(); // Output: Jack Smith
⚠️ Note: In production code, it's not recommended to modify
Function.prototype
directly.
To create a polyfill safely, always check if the method already exists before defining it:
if (!Function.prototype.myBind) { Function.prototype.myBind = function (...) { // your polyfill logic here }; }
So far, so good! This handles the basic functionality of setting the this
context.
What If We Want to Pass Arguments?
let name = {
firstName: 'Jack',
lastName: 'Smith',
};
let printFullName = function(hometown, state) {
console.log(this.firstName + ' ' + this.lastName, 'from', hometown, state);
};
// custom bind function
Function.prototype.myBind = function (...args) {
let func = this;
let obj = args[0]
return function () {
func.apply(obj);
};
};
let printMyName = printFullName.myBind(name, 'Hyderabad', 'Telangana');
printMyName(); // Output: Jack Smith from undefined undefined
We passed arguments, but it didn’t show up in the output. That’s because our polyfill doesn’t forward the arguments yet.
Fixing It: Forward the Arguments
let name = {
firstName: 'Jack',
lastName: 'Smith',
};
let printFullName = function(hometown, state) {
console.log(this.firstName + ' ' + this.lastName, 'from', hometown, state);
};
// custom bind function
Function.prototype.myBind = function (...args) {
let func = this;
let obj = args[0]
let params = args.slice(1) // First argument is the object we want to point to, the rest are the arguments we want to pass to the function
return function () {
func.apply(obj, params);
};
};
let printMyName = printFullName.myBind(name, 'Hyderabad', 'Telangana');
printMyName(); // Output: Jack Smith from Hyderabad Telangana
What If We Also Pass Arguments While Calling?
let name = {
firstName: 'Jack',
lastName: 'Smith',
};
let printFullName = function(hometown, state, country) {
console.log(this.firstName + ' ' + this.lastName, 'from', hometown, state, country);
};
// custom bind function
Function.prototype.myBind = function (...args) {
let func = this;
let obj = args[0]
let params = args.slice(1)
return function () {
func.apply(obj, params);
};
};
let printMyName = printFullName.myBind(name, 'Hyderabad', 'Telangana');
printMyName('India'); // Output: Jack Smith from Hyderabad Telangana undefined
We want to pass 'India'
during the function call, but our current polyfill ignores those.
Support Both Bind-Time and Call-Time Arguments
let name = {
firstName: 'Jack',
lastName: 'Smith',
};
let printFullName = function(hometown, state, country) {
console.log(this.firstName + ' ' + this.lastName, 'from', hometown, state, country);
};
// custom bind function
Function.prototype.myBind = function (...args) {
let func = this;
let obj = args[0]
let params = args.slice(1)
// Accepting arguments passed to printMyName
return function (...args2) {
func.apply(obj, [...params, ...args2]);
};
};
let printMyName = printFullName.myBind(name, 'Hyderabad', 'Telangana');
printMyName('India'); // Output: Jack Smith from Hyderabad Telangana India
This version of myBind()
correctly handles:
Setting
this
Partially applying arguments
Receiving additional arguments at call time
Final Thoughts
With our custom implementation of bind()
, we’ve essentially written a polyfill — a fallback implementation for older environments that might not support the native method.
Through this exercise, we’ve learned:
How the native
bind()
method works under the hoodHow to handle function context (
this
)How argument forwarding and partial application works
How to create your own polyfill for real-world methods
Thanks for Reading!
I hope this post helped you understand polyfills and how to build one for bind()
in JavaScript. If you found this helpful, share it with your dev friends and let me know your thoughts in the comments.
Happy coding!
Subscribe to my newsletter
Read articles from Deepthi Purijala directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Deepthi Purijala
Deepthi Purijala
Full Stack Developer with hands-on experience of more than 1 year. Proficient in both Back-end and Front-end technologies, with a strong commitment to delivering high-quality code