原型和原型链

在 JavaScript 中,每个对象都有一个原型对象(prototype),原型对象又是一个对象,如果我们在原型对象上添加属性或方法,这些属性和方法会被该原型对象上的所有对象所共享,因为它们都继承自该原型对象。这就是 JavaScript 中的原型(prototype)。

而原型链是指当我们访问一个对象的属性或方法时,如果该对象自身没有该属性或方法,它就会沿着原型链向上查找,直到找到该属性或方法或者查找到原型链的顶端(即 Object.prototype)为止。这个过程就是 JavaScript 中的原型链(prototype chain)。

举个例子,我们定义一个构造函数 Person

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}

const john = new Person('John', 30);

在上述例子中,我们通过 Person 构造函数创建了一个名为 john 的对象,并通过 Person.prototype 对象为 Person 的实例 john 添加了一个 sayHello 方法。当我们调用 john.sayHello() 时,JavaScript 引擎首先会查找 john 对象是否有 sayHello 方法,如果没有,它就会沿着原型链查找,最终找到了 Person.prototype 对象上的 sayHello 方法,然后调用该方法并传入 john 对象作为上下文对象(也就是 this)。

我们可以通过 Object.getPrototypeOf() 方法来查看对象的原型:

console.log(Object.getPrototypeOf(john) === Person.prototype); // true

我们也可以通过 __proto__ 属性来访问对象的原型:

console.log(john.__proto__ === Person.prototype); // true

由于原型链的存在,我们还可以给 Person.prototype 的原型对象 Object.prototype 添加方法,从而让 Person 的实例 john 继承该方法:

Object.prototype.sayGoodbye = function() {
  console.log('Goodbye!');
};

john.sayGoodbye(); // "Goodbye!"

在上述例子中,当我们调用 john.sayGoodbye() 时,JavaScript 引擎首先在 john 对象上查找 sayGoodbye 方法,发现没有,然后沿着原型链查找,找到了 Object.prototype 对象上的 sayGoodbye 方法,然后调用该方法并传入 john 对象作为上下文对象(也就是 this)。