Mastering JavaScript's Function Context Methods: call(), apply(), and bind()

1. call()
Effect: Executes a function immediately and sets the this
context.
Syntax: function.call(thisArg, arg1, arg2, ...)
Example:
1 function greet(greeting, punctuation) {2 console.log(greeting + ", " + this.name + punctuation);3 }4 const obj = { name: "Alice" };5 greet.call(obj, "Hello", "!"); // Output: Hello, Alice!
2. apply()
Effect: Similar to call
, but parameters are passed as an array.
Syntax: function.apply(thisArg, [argsArray])
Example:
1 function greet(greeting, punctuation) {2 console.log(greeting + ", " + this.name + punctuation);3 }4 const obj = { name: "Bob" };5 greet.apply(obj, ["Hi", "!!"]); // Output: Hi, Bob!!
3. bind()
Effect: Returns a new function with this
permanently bound.
Syntax: function.bind(thisArg, arg1, arg2, ...)
Example:
1 function greet(greeting, punctuation) {2 console.log(greeting + ", " + this.name + punctuation);3 }4 const obj = { name: "Charlie" };5 const boundGreet = greet.bind(obj, "Hey");6 boundGreet("!!!"); // Output: Hey, Charlie!!!
Handwritten Implementations
Implementing call()
Steps:
- Verify that the caller is a function.
- Handle the
context
argument (convertnull
orundefined
toglobalThis
). - Assign a temporary function property to
context
. - Execute the function and return the result.
- Clean up the temporary property.
Implementation:
1 Function.prototype.myCall = function (context, ...args) {2 if (typeof this !== "function") {3 throw new TypeError("Caller is not a function");4 }5 context = context == null ? globalThis : Object(context);6 const key = Symbol("temp");7 Object.defineProperty(context, key, { value: this, enumerable: false });8 try {9 return context[key](...args);10 } finally {11 delete context[key];12 }13 };
Implementing apply()
Steps:
- Verify the caller is a function.
- Ensure the second argument is an array.
- Handle
context
argument similarly tocall
. - Assign a temporary function property to
context
. - Execute the function with the provided array arguments.
- Clean up the temporary property.
Implementation:
1 Function.prototype.myApply = function (context, args) {2 if (typeof this !== "function") {3 throw new TypeError("Caller is not a function");4 }5 if (!Array.isArray(args)) {6 throw new TypeError("The parameter must be an array");7 }8 context = context == null ? globalThis : Object(context);9 const key = Symbol("temp");10 context[key] = this;11 try {12 return context[key](...args);13 } finally {14 delete context[key];15 }16 };
Implementing bind()
Steps:
- Verify that the caller is a function.
- Handle the
context
argument. - Store the original function and predefined arguments.
- Return a new function that merges predefined and new arguments.
- Ensure the prototype chain is maintained.
Implementation:
1 Function.prototype.myBind = function (context, ...args) {2 if (typeof this !== "function") {3 throw new TypeError(4 "Function.prototype.myBind - what is trying to be bound is not callable"5 );6 }7 context = context == null ? globalThis : Object(context);8 const fn = this;9 const bound = function (...innerArgs) {10 const allArgs = args.concat(innerArgs);11 if (this instanceof bound) {12 return new fn(...allArgs);13 } else {14 return fn.apply(context, allArgs);15 }16 };17 if (fn.prototype) {18 bound.prototype = Object.create(fn.prototype);19 }20 return bound;21 };
Summary
call()
andapply()
execute functions immediately with a specifiedthis
context
.apply()
differs fromcall()
by passing arguments as an array.bind()
returns a new function with permanently boundthis
, allowing partial application.- Handwritten implementations use
Symbol
for temporary property names to avoid conflicts.
By understanding and implementing these methods manually, developers can deepen their grasp of JavaScript's function execution context and scope.