返回

JavaScript 原型及其精妙构造的奥秘:原型链与继承方式揭秘

前端

初识原型

在 JavaScript 中,每个函数都有一个原型对象,该对象包含指向构造函数的指针,同时还包含一组属性和方法。当使用 new 运算符创建实例时,该实例就继承了原型对象中的属性和方法。

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

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
};

const person1 = new Person('John Doe');
person1.greet(); // Hello, my name is John Doe.

上例中,Person 函数的原型对象包含一个名为 greet 的方法,当使用 new 运算符创建 person1 实例时,该实例就继承了 greet 方法,并可以通过实例调用该方法。

原型链的奥妙

JavaScript 中的原型链是指原型对象之间的连接关系。每个对象都包含一个指向其原型对象的指针,而原型对象又包含指向其原型对象的指针,如此递归地连接下去。当访问一个对象的属性或方法时,JavaScript 会沿着原型链向上查找,直到找到该属性或方法。

const person1 = new Person('John Doe');

console.log(person1.name); // John Doe
console.log(person1.greet()); // Hello, my name is John Doe.

// 原型链上的查找
console.log(person1.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true

上例中,person1 实例的 __proto__ 属性指向 Person 函数的原型对象,而 Person 函数的原型对象的 __proto__ 属性指向 Object 函数的原型对象。当访问 person1 实例的 name 属性时,JavaScript 会沿着原型链向上查找,直到找到 Person 函数的原型对象中的 name 属性,并将其值返回。同样,当调用 person1 实例的 greet 方法时,JavaScript 会沿着原型链向上查找,直到找到 Person 函数的原型对象中的 greet 方法,并执行该方法。

巧用原型链实现继承

JavaScript 中的继承是指一个对象从另一个对象继承属性和方法。在 JavaScript 中,原型链为实现继承提供了天然的方式。子类可以通过将原型对象指向父类的原型对象来继承父类的属性和方法。

function Employee(name, salary) {
  Person.call(this, name);
  this.salary = salary;
}

Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;

const employee1 = new Employee('Jane Doe', 5000);

console.log(employee1.name); // Jane Doe
console.log(employee1.salary); // 5000
console.log(employee1.greet()); // Hello, my name is Jane Doe.

上例中,Employee 函数的原型对象被设置为 Object.create(Person.prototype),这表示 Employee 函数的原型对象继承了 Person 函数的原型对象中的所有属性和方法。当使用 new 运算符创建 employee1 实例时,该实例就继承了 Person 函数的原型对象中的属性和方法,同时也继承了 Employee 函数的原型对象中的属性和方法。

总结

JavaScript 中的原型、原型链和继承是密切相关的概念。原型对象包含指向构造函数的指针,以及一组属性和方法。原型链是指原型对象之间的连接关系。继承是指一个对象从另一个对象继承属性和方法。通过理解这些概念,可以更好地理解 JavaScript 的对象模型和继承机制。