Yuan's Blog
EN

Prototype, Prototype Chain, and Prototypal Inheritance

Prototype, Prototype Chain, and Prototypal Inheritance

  • prototype and __proto__ are different: prototype exists 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: this is dynamic. It is determined by how a function is called, not how it is declared. Whoever calls the function becomes the this value for that call.
  1. Function call:When a function is called not as a method of an object but as a plain function, this refers to the global object.
  • In the browser, this is window.
  • However, in strict mode, this will be undefined.
var name = "John";
function callThis() {
  console.log(this);
  console.log(this.name);
}
callThis();
// Window
// John
  1. Method call on an object:When a function is invoked as a method of an object, this refers to that object.
const john = {
  name: "john",
  callJohn() {
    console.log(`hello, ${this.name}`);
  },
};

john.callJohn(); // hello, john
  1. Constructor call: When a function is invoked with the new keyword, a new object is created before the function executes, and this refers 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
  1. apply, call, and bind calls (manually setting this):These methods allow you to explicitly specify the value of this when 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
  1. this in arrow functions:The this value 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 default this.

What is class in ES6? How is it different from constructor functions?

  1. Common method inheritance with class:In this example, the Dog class inherits all properties and methods from the Animal class, and can also override the speak method.
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.`);
  }
}
  1. static methods: 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
  1. 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.assign
      let 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.