1. What does the this
keyword refer to in JavaScript?
Core Concept: Understanding the dynamic nature of this
and its different bindings.
Standard Answer: In JavaScript, the this
keyword is a special identifier that is automatically defined in the scope of every function. Its value is determined by how a function is called, which is known as its "execution context." It doesn't refer to the function itself, but rather to the object that the function is a method of.
- In the global context (outside of any function),
this
refers to the global object, which iswindow
in a browser orglobal
in Node.js. - When a function is called as a method of an object (
object.myMethod()
),this
is bound to the object the method is called on. - When a function is called as a standalone function (not attached to an object),
this
will default to the global object in non-strict mode, or beundefined
in strict mode. - With arrow functions,
this
is lexically bound, meaning it inherits thethis
value from its surrounding (enclosing) scope at the time of its creation. - When used with
call
,apply
, orbind
,this
is explicitly set to the object passed as the first argument.
Possible Follow-up Questions:
๐ (Want to test your skills? Try a Mock Interviews)
- How does "strict mode" (
'use strict'
) affect thethis
keyword? - Can you explain the difference between dynamic scope (how
this
works) and lexical scope? - What happens to
this
inside a function that is used as an event handler?
2. What is the output of the following code and why?
const user = {
name: 'John Doe',
greet: function() {
console.log(`Hello, I'm ${this.name}`);
},
farewell: () => {
console.log(`Goodbye from ${this.name}`);
}
};
user.greet();
user.farewell();
Core Concept: Differentiating this
in a regular function versus an arrow function within an object.
Standard Answer:
-
user.greet()
will output: "Hello, I'm John Doe". This is becausegreet
is a regular function and it's called as a method of theuser
object. Therefore,this
insidegreet
refers to theuser
object itself. -
user.farewell()
will output: "Goodbye from undefined" (or an empty string, depending on the environment). This is becausefarewell
is an arrow function. Arrow functions do not have their ownthis
binding; they inheritthis
from their parent scope. In this case, the parent scope is the global scope wherethis.name
is not defined.
Possible Follow-up Questions:
๐ (Want to test your skills? Try a Mock Interviews)
- How could you modify the
farewell
method to correctly print "John Doe" while still keeping it as a property on theuser
object? - If this code were running inside another function, what would
this
refer to for thefarewell
function? - What if we assigned
greet
to a new variable and then called it? For example:const sayHello = user.greet; sayHello();
What would be the output?
3. What are call
and apply
, and what is the main difference between them?
Core Concept: Understanding explicit this
binding and how arguments are passed.
Standard Answer: Both call
and apply
are methods that exist on all JavaScript functions. They allow you to invoke a function and explicitly specify the this
context for that function call. This means you can "borrow" a function and have it execute in the context of an object it wasn't originally defined on.
The main difference lies in how they handle function arguments:
-
.call(thisArg, arg1, arg2, ...)
accepts thethis
context as its first argument, followed by a comma-separated list of arguments for the function it's invoking. -
.apply(thisArg, [arg1, arg2, ...])
accepts thethis
context as its first argument, and the second argument must be an array (or an array-like object) containing the arguments for the function.
A simple mnemonic is: C for call
and comma, A for apply
and array.
Possible Follow-up Questions:
๐ (Want to test your skills? Try a Mock Interviews)
- Can you give a practical example where
apply
would be more convenient thancall
? (Hint: think about dynamic arguments). - What happens if you pass
null
orundefined
as the first argument tocall
orapply
? - Before the spread syntax (
...
), how wasapply
commonly used with arrays for functions likeMath.max()
?
4. What is bind
and how does it differ from call
and apply
?
Core Concept: Explaining how bind
creates a new function with a permanently bound this
.
Standard Answer: The .bind()
method also allows you to set the this
value for a function. However, unlike call
and apply
which execute the function immediately, .bind()
returns a new function with the this
keyword permanently bound to the provided value. This new function can be called later.
The key differences are:
- Execution:
call
andapply
invoke the function immediately.bind
returns a new function that you can execute later. - Arguments: You can pass arguments to
bind
just like you do withcall
(a comma-separated list). This is known as "partial application" or "currying," where you pre-fill some of the arguments.
Possible Follow-up Questions:
๐ (Want to test your skills? Try a Mock Interviews)
- Can you provide a common use case for
bind
, for example, with event listeners or in React class components? - Once a function has been bound, can you change its
this
context again usingcall
orapply
? Why or why not? - How could you implement your own simple version of the
bind
function?
5. Explain the output of this code snippet:
var name = "Global";
function printName() {
console.log(this.name);
}
const obj1 = {
name: "Object 1",
print: printName
};
const obj2 = {
name: "Object 2",
print: printName
};
const boundPrint = printName.bind(obj1);
boundPrint();
obj2.print.call(obj1);
Core Concept: Testing the understanding of method calls, explicit binding with bind
and call
, and binding precedence.
Standard Answer:
-
boundPrint()
will output "Object 1". This is becausebind
creates a new function wherethis
is permanently set toobj1
. When we callboundPrint()
, it executesprintName
with that pre-configured context. -
obj2.print.call(obj1)
will also output "Object 1". Although we are accessing the function throughobj2
, the.call(obj1)
method immediately invokes it and explicitly sets thethis
context toobj1
, overriding the default context ofobj2
.
Possible Follow-up Questions:
๐ (Want to test your skills? Try a Mock Interviews)
- What would be the output if we just called
obj2.print()
? - What if we tried this:
const newBound = boundPrint.bind(obj2); newBound();
What would it log and why? - How does the concept of "binding precedence" rank
bind
vs.call
/apply
?
6. How can you use call
or apply
to borrow methods from other objects?
Core Concept: Demonstrating practical application of explicit binding for code reuse.
Standard Answer: You can borrow methods by using call
or apply
to invoke a method from one object on another object that doesn't have that method. A classic example is using array methods on arguments
, which is an array-like object but not a true array.
For example, to use the slice
method on the arguments
object to convert it into a real array:
function list() {
// arguments is not a real array, so it doesn't have .slice()
// We "borrow" slice from Array.prototype
const argsArray = Array.prototype.slice.call(arguments);
return argsArray;
}
console.log(list(1, 2, 3)); // [1, 2, 3]
Here, we are calling the slice
method and telling it that its this
should be the arguments
object, allowing it to work as intended.
Possible Follow-up Questions:
๐ (Want to test your skills? Try a Mock Interviews)
- Can you show another example, perhaps borrowing
forEach
to iterate over aNodeList
fromdocument.querySelectorAll
? - What makes an object "array-like"? What properties must it have for this to work?
- Besides
arguments
andNodeList
, can you name other array-like objects in JavaScript?
7. What is "binding precedence" in JavaScript?
Core Concept: Ranking the different ways this
can be determined.
Standard Answer: Binding precedence is the set of rules JavaScript uses to determine the value of this
when multiple rules could apply. The order of precedence, from highest to lowest, is:
-
new
binding: When a function is called with thenew
keyword (as a constructor),this
is a newly created object. This has the highest precedence. - Explicit binding: When a function is called using
call
,apply
, orbind
,this
is explicitly set to the object passed as the first argument. - Implicit binding: When a function is called as a method of an object (
obj.method()
),this
is bound to that object. - Default binding: If none of the above rules apply,
this
defaults to the global object (window
in browsers) in non-strict mode, orundefined
in strict mode.
Note: Arrow functions are an exception; they don't follow these rules and instead take the this
of their lexical parent scope.
Possible Follow-up Questions:
๐ (Want to test your skills? Try a Mock Interviews)
- Can you write a piece of code that demonstrates
new
binding taking precedence overbind
? - Where do arrow functions fit into this hierarchy?
- Explain why
obj.method.call(anotherObj)
is an example of explicit binding overriding implicit binding.
8. What is a hard-binding and how can you achieve it?
Core Concept: Understanding how to create a function that is permanently locked to a specific this
context.
Standard Answer: Hard-binding is the process of creating a function that, no matter how it's called, is always bound to a specific this
context. The most common and modern way to achieve this is by using the .bind()
method.
When you use func.bind(obj)
, it creates a new function that is permanently "hard-bound" to obj
. Any subsequent attempts to change its this
context using call
, apply
, or even implicit binding will be ignored.
Here is an example:
function sayName() {
console.log(this.name);
}
const user = { name: "Alice" };
const otherUser = { name: "Bob" };
const boundSayName = sayName.bind(user);
boundSayName(); // Logs "Alice"
boundSayName.call(otherUser); // Still logs "Alice"
The hard-binding to user
cannot be overridden.
Possible Follow-up Questions:
๐ (Want to test your skills? Try a Mock Interviews)
- Before
.bind()
was introduced in ES5, how might a developer have created a hard-bound function? (Hint: using a closure). - Is an arrow function a form of hard-binding? Explain your reasoning.
- Can you use hard-binding to create a function that ignores the
this
from anew
keyword instantiation?
9. How does this
work with constructor functions?
Core Concept: Explaining the new
binding rule.
Standard Answer: When a function is called using the new
keyword, it acts as a constructor. JavaScript does four things automatically:
- A brand new, empty object is created.
- This new object is linked to the function's
prototype
. - The
this
keyword inside the constructor function is bound to this newly created object. - If the function does not explicitly return another object, it implicitly returns
this
(the new object).
So, inside a constructor function, this
refers to the new instance of the object being created.
function Car(make) {
// `this` here refers to the new object being created
this.make = make;
this.isRunning = false;
}
const myCar = new Car('Honda'); // `this` inside Car was bound to myCar
console.log(myCar.make); // "Honda"
Possible Follow-up Questions:
๐ (Want to test your skills? Try a Mock Interviews)
- What happens if you forget to use the
new
keyword when calling a constructor function? - What happens if you explicitly
return
a primitive value (like a string or number) from a constructor? - What happens if you explicitly
return
an object from a constructor?
10. Can you implement your own version of Function.prototype.bind
?
Core Concept: Demonstrating a deep understanding of closures, this
, and apply
by creating a polyfill.
Standard Answer: Yes. A custom bind
function needs to do three things:
- Accept a context (
thisArg
) and return a new function. - Capture any arguments passed during the binding phase ("partial application").
- When the new function is called, it should invoke the original function with the bound context and a combination of the bound arguments and any new arguments.
Here's a simplified implementation:
Function.prototype.myBind = function(context, ...boundArgs) {
const originalFunc = this; // 'this' here is the function myBind is called on
// Return a new function
return function(...newArgs) {
// When the new function is called, invoke the original
// with the saved context and all arguments.
return originalFunc.apply(context, [...boundArgs, ...newArgs]);
};
};
// Example Usage:
function greet(greeting, punctuation) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
const person = { name: 'Sarah' };
const greetSarah = greet.myBind(person, 'Hello');
greetSarah('!'); // Outputs: "Hello, Sarah!"
Possible Follow-up Questions:
๐ (Want to test your skills? Try a Mock Interviews)
- My implementation uses
apply
and spread syntax. How could you achieve the same result without them? - A complete polyfill for
bind
also needs to handle being used with thenew
operator. How would you add that functionality? - What are the advantages of creating polyfills like this?
Top comments (0)