基本概念
在 JavaScript 中,每个对象都有一个内部属性 `[[Prototype]]`(在浏览器中可以通过 `__proto__` 访问,不过不建议在代码里直接使用),这个属性指向该对象的原型对象。而函数作为 JavaScript 里的一等公民,有一个特殊的属性 `prototype`,当函数作为构造函数使用时,通过 `new` 关键字创建的对象的 `[[Prototype]]` 会指向构造函数的 `prototype` 属性。
使用方式
1. 构造函数与 `prototype`
可以借助构造函数和 `prototype` 属性来创建对象并实现属性和方法的共享。
javascript
// 定义一个构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
// 在构造函数的 prototype 上添加方法
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
};
// 创建对象实例
const person1 = new Person('John', 30);
const person2 = new Person('Jane', 25);
// 调用共享方法
person1.sayHello();
person2.sayHello();
在上述代码中,`Person` 是一个构造函数,`Person.prototype.sayHello` 为所有通过 `new Person()` 创建的对象添加了一个共享方法。
2. 修改 `prototype`
能够随时修改构造函数的 `prototype` 属性,从而影响后续创建的对象。
javascript
function Animal() {}
// 初始时 prototype 上有一个方法
Animal.prototype.makeSound = function() {
console.log('Some generic sound');
};
const animal1 = new Animal();
animal1.makeSound();
// 修改 prototype
Animal.prototype.makeSound = function() {
console.log('A different sound');
};
const animal2 = new Animal();
animal2.makeSound();
原型链
当访问一个对象的属性或方法时,JavaScript 首先会在对象本身查找,如果找不到,就会沿着原型链向上查找,直到找到该属性或方法,或者到达原型链的末尾(即 `Object.prototype`)。
javascript
function GrandParent() {}
GrandParent.prototype.grandParentMethod = function() {
console.log('GrandParent method');
};
function Parent() {}
Parent.prototype = Object.create(GrandParent.prototype);
Parent.prototype.parentMethod = function() {
console.log('Parent method');
};
function Child() {}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.childMethod = function() {
console.log('Child method');
};
const child = new Child();
child.childMethod();
child.parentMethod();
child.grandParentMethod();
在这个例子中,`Child` 对象的原型链依次为 `Child.prototype` -> `Parent.prototype` -> `GrandParent.prototype` -> `Object.prototype`。
与 `class` 语法的关系
ES6 引入了 `class` 语法糖,它本质上还是基于原型的继承,只是语法更加简洁和直观。
javascript
// 使用 class 语法
class Vehicle {
constructor(type) {
this.type = type;
}
move() {
console.log(`${this.type} is moving`);
}
}
class Car extends Vehicle {
constructor() {
super('Car');
}
}
const myCar = new Car();
myCar.move();
这里 `Car` 类继承自 `Vehicle` 类,在底层依然是通过原型链来实现继承的。
总结
`prototype` 是 JavaScript 实现继承和属性共享的核心机制,理解它对于掌握 JavaScript 的面向对象编程至关重要。尽管 ES6 引入了 `class` 语法,但 `prototype` 依然是 JavaScript 底层的重要组成部分。