JavaScript 是一种动态类型的编程语言,其核心特性之一就是对象和原型链。理解原型及其工作机制对于掌握 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
对象的属性和方法。