Prototype, Prototype Chain, and Prototypal Inheritance
Prototype, Prototype Chain, and Prototypal Inheritance
prototypeand__proto__are different:prototypeexists on functions, while__proto__is a property of objects.[[Prototype]]is a special internal hidden property of JavaScript objects. Since it cannot be accessed directly, it can be reached through the__proto__accessor.- When we add properties or methods to a function’s
prototype, every object instantiated from that function can access those shared properties or methods.
// Constructor function Animal
function Animal() {}
// Instance
const cat = new Animal();
// Add a method to the prototype object
Animal.prototype.sleep = function () {
console.log("sleep");
};
// Use the method defined on the constructor's prototype
cat.sleep(); // sleep
Explain the value of this in JavaScript
- There are five ways to determine the value of
this:thisis dynamic. It is determined by how a function is called, not how it is declared. Whoever calls the function becomes thethisvalue for that call.
- Function call:When a function is called not as a method of an object but as a plain function,
thisrefers to the global object.
- In the browser, this is
window. - However, in strict mode,
thiswill beundefined.
var name = "John";
function callThis() {
console.log(this);
console.log(this.name);
}
callThis();
// Window
// John
- Method call on an object:When a function is invoked as a method of an object,
thisrefers to that object.
const john = {
name: "john",
callJohn() {
console.log(`hello, ${this.name}`);
},
};
john.callJohn(); // hello, john
- Constructor call: When a function is invoked with the
newkeyword, a new object is created before the function executes, andthisrefers to that newly created object.
function Cellphone(brand) {
this.brand = brand;
}
Cellphone.prototype.getBrand = function () {
return this.brand;
};
let newIPhone = new Cellphone("Apple");
let newPixelPhone = new Cellphone("Google");
console.log(newIPhone.getBrand()); // Apple
console.log(newPixelPhone.getBrand()); // Google
apply,call, andbindcalls (manually settingthis):These methods allow you to explicitly specify the value ofthiswhen invoking a function.
- call:fn.call(thisArg, arg1, arg2, …)
function greet(greeting) {
console.log(greeting, this.name);
}
const user = { name: "Tom" };
greet.call(user, "Hello"); // Hello Tom
- apply:fn.apply(thisArg, [arg1, arg2])
function sum(a, b, c) {
return a + b + c;
}
console.log(sum.apply(null, [1, 2, 3])); // 6
- bind:const newFn = fn.bind(thisArg, arg1, arg2)
function sum(a, b, c) {
return a + b + c;
}
console.log(sum.apply(null, [1, 2, 3])); // 6
thisin arrow functions:Thethisvalue inside an arrow function is lexically inherited from its outer function.If the outer function is also an arrow function, the lookup continues upward until it reaches the global scope’s defaultthis.
What is class in ES6? How is it different from constructor functions?
- Common method inheritance with
class:In this example, theDogclass inherits all properties and methods from theAnimalclass, and can also override thespeakmethod.
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} eat food.`);
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
speak() {
console.log(`${this.name} barks.`);
}
}
staticmethods: Static methods cannot be inherited by instances of the class; they can only be called directly on the class itself. This means you cannot call a static method from an instance — only from the class name.
class MathHelper {
static add(a, b) {
return a + b;
}
}
const math = new MathHelper();
console.log(math.add(2, 3)); // Uncaught TypeError: math.add is not a function
console.log(MathHelper.add(2, 3)); // 5
- Private fields:By using the
#prefix, a class can define private fields — including private properties or methods.These private members can only be accessed inside the class and are completely inaccessible from the outside.
class Example {
#privateField = 100;
getPrivateField() {
return this.#privateField;
}
}
const example = new Example();
console.log(example.getPrivateField()); // 100
console.log(example.#privateField); // SyntaxError: Private field '#privateField' must be declared in an enclosing class
What is the difference between shallow copy and deep copy in JavaScript? How do you implement them?
A shallow copy only copies the first level of properties. If a property is a primitive type (number, string, boolean), its value is copied. If a property is an object or array, only the reference is copied — no new independent object is created.
- Method 1: Manually copy values
- Method 2: Use spread syntax
- Method 3: Use
Object.assignlet objB = Object.assign({}, objA);
A deep copy recursively copies every level of the object so that everything is completely independent. All nested objects receive new memory locations and do not share references.
JSON.parse(JSON.stringify(...)): This converts the object into JSON text and then rebuilds a new object. It performs deep copy for data that can be JSON-serialized. It does not support functions,Date,RegExp,Map/Set, or cyclic references.- Use
structuredClone(value)for a more complete and modern deep-copy solution.