JavaScript 是一种动态类型的编程语言,其核心特性之一就是对象和原型链。理解原型及其工作机制对于掌握 JavaScript 的继承和对象关系非常重要。

【Web前端】JavaScript 对象原型与继承机制_构造函数


什么是原型

每个对象都有一个内部属性 [[Prototype]],这个属性指向创建该对象的构造函数的原型对象。这个内部属性通常被称为原型链(prototype chain)。原型链是 JavaScript 实现继承和属性查找的基础机制。


原型链的工作机制

原型链是一种用于实现继承的机制。当你访问一个对象的属性时,JavaScript 会首先在对象本身上寻找这个属性。如果在对象本身上找不到这个属性,它会沿着原型链向上查找,直到找到这个属性或者到达原型链的顶端。

代码示例

const person = {
  name: 'Xianyu',
  age: 23
};

const child = Object.create(person);
child.job = 'Student';

console.log(child.name); // Xianyu
console.log(child.age); // 23
console.log(child.job); // Student

示例中 child 对象的原型是 person 对象。当我们访问 child.name 和 child.age 时,JavaScript 会首先在 child 对象上寻找这些属性。如果在 child 对象上找不到这些属性,它会沿着原型链向上查找,找到 person 对象上的 name 和 age 属性。


设置原型

JavaScript 中有多种方式可以为一个对象设置原型。主要有三种方式:使用 Object.create、使用构造函数和自有属性。

使用 Object.create

Object.create 方法是 JavaScript 中为对象设置原型的最常用方式。它允许你创建一个新对象,并指定这个新对象的原型。

const person = {
  name: 'Xianyu',
  age: 23
};

const child = Object.create(person);
child.job = 'Student';

console.log(child.name); // Xianyu
console.log(child.age); // 23
console.log(child.job); // Student

child 对象的原型是 person 对象。


使用构造函数

构造函数是另一种为对象设置原型的方式。每个构造函数都有一个 prototype 属性,这个属性指向构造函数的原型对象。

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

const person = new Person('Xianyu', 23);
const child = new person.constructor();
child.job = 'Student';

console.log(child.name); // undefined
console.log(child.age); // undefined
console.log(child.job); // Student

示例中child 对象的原型是 Person.prototype


自有属性

自有属性是对象本身上定义的属性,而不是通过原型链继承的属性。自有属性的优先级高于原型链上的属性。

const person = {
  name: 'Xianyu',
  age: 23
};

const child = Object.create(person);
child.name = 'Xianyadan';
child.age = 22;
child.job = 'engineer';

console.log(child.name); // Xianyadan
console.log(child.age); // 22
console.log(child.job); // engineer

child 对象有自有属性 name 和 age,这些自有属性会遮蔽原型链上的同名属性。


属性遮蔽

属性遮蔽是指自有属性会遮蔽原型链上的同名属性。当你访问一个对象的属性时,JavaScript 会首先查找自有属性,如果找到了,就不会再沿着原型链向上查找。

代码示例

const person = {
  name: 'Xianyu',
  age: 23
};

const child = Object.create(person);
child.name = 'Xianyadan';
child.age = 22;

console.log(child.name); // Xianyadan
console.log(child.age); // 22

示例中child 对象有自有属性 name 和 age,这些自有属性会遮蔽原型链上的同名属性。


原型与继承

JavaScript 通过原型链实现继承。继承是指一个对象可以继承另一个对象的属性和方法。通过设置对象的原型,我们可以实现对象之间的继承关系。

代码示例

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

Person.prototype.sayHello = function() {
  console.log('Hello, I am ' + this.name);
};

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

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

const student = new Student('Xianyu', 23, 'A');
student.sayHello(); // Hello, I am Xianyu
console.log(student.grade); // A

Student 构造函数通过调用 Person 构造函数来继承 Person 对象的属性和方法。Student.prototype 被设置为 Person.prototype 的一个实例,从而实现了 Student 对象继承 Person 对象的属性和方法。