JavaScript 基础特性:原型与原型链

原创
admin 6个月前 (06-11) 阅读数 233 #JavaScript

什么是原型和原型链?

在 JavaScript 中,每个函数都有一个 prototype 属性,这个属性指向一个对象,称为该函数的原型对象。当通过构造函数创建一个实例时,该实例会继承原型对象上的属性和方法。

原型链是 JavaScript 实现继承的核心机制。每个对象都有一个内部属性 [[Prototype]](可以通过 Object.getPrototypeOf()__proto__ 访问),它指向创建该对象的构造函数的 prototype 对象。如果在对象上找不到某个属性或方法,JavaScript 会沿着原型链向上查找,直到找到该属性或方法,或者到达原型链的尽头(即 null)。


代码示例

1. 原型的基本使用
function Person(name) {    this.name = name;}// 在原型上定义方法Person.prototype.sayHello = function() {    console.log(`Hello, my name is ${this.name}`);};const person1 = new Person('Alice');person1.sayHello(); // 输出: Hello, my name is Aliceconsole.log(person1.__proto__ === Person.prototype); // trueconsole.log(Person.prototype.isPrototypeOf(person1)); // true

解释

Person 是一个构造函数,Person.prototype 是它的原型对象。person1 是通过 new Person() 创建的实例,它的 [[Prototype]] 指向 Person.prototype。调用 person1.sayHello() 时,JavaScript 会在 person1 上找不到 sayHello 方法,于是沿着原型链查找,最终在 Person.prototype 上找到了该方法。
2. 原型链的继承
function Animal(type) {    this.type = type;}Animal.prototype.move = function() {    console.log(`${this.type} is moving`);};function Dog(name) {    this.name = name;}// 继承 Animal 的原型Dog.prototype = Object.create(Animal.prototype);Dog.prototype.constructor = Dog;Dog.prototype.bark = function() {    console.log(`${this.name} is barking`);};const dog1 = new Dog('Buddy');dog1.move(); // 输出: Dog is movingdog1.bark(); // 输出: Buddy is barking

解释

Dog.prototype 被设置为 Animal.prototype 的一个新实例,从而实现了继承。dog1 可以访问 Animal.prototype 上的 move 方法,以及 Dog.prototype 上的 bark 方法。
3. 原型链的尽头
const obj = {};console.log(Object.getPrototypeOf(obj) === Object.prototype); // trueconsole.log(Object.getPrototypeOf(Object.prototype)); // null

解释

所有普通对象的原型最终都会指向 Object.prototypeObject.prototype 的原型是 null,表示原型链到此结束。

原型链的特点

动态性:修改原型对象会影响所有基于该原型创建的实例。

function Car() {}const car1 = new Car();Car.prototype.drive = function() {    console.log('Driving...');};car1.drive(); // 输出: Driving...

共享性:多个实例共享同一个原型对象上的属性和方法,节省内存。

function Book(title) {    this.title = title;}Book.prototype.read = function() {    console.log(`Reading "${this.title}"`);};const book1 = new Book('Book A');const book2 = new Book('Book B');book1.read(); // 输出: Reading "Book A"book2.read(); // 输出: Reading "Book B"

查找顺序:先在实例自身查找属性或方法,如果找不到,则沿着原型链向上查找。


注意事项

避免在原型上定义可变数据类型:如果在原型上定义数组或对象等可变数据类型,所有实例会共享同一个引用,可能导致意外行为。

function User() {}User.prototype.hobbies = [];const user1 = new User();const user2 = new User();user1.hobbies.push('Reading');console.log(user2.hobbies); // 输出: ['Reading']

正确重写原型:如果重写了构造函数的原型,需要手动恢复 constructor 属性。

function Cat() {}Cat.prototype = {    constructor: Cat,    meow: function() {        console.log('Meow!');    }};const cat1 = new Cat();console.log(cat1 instanceof Cat); // true

总结

原型和原型链是 JavaScript 中非常重要的特性,理解它们的工作原理可以帮助开发者更好地设计类和对象,实现代码复用和继承。通过本文的示例,我们了解了如何使用原型添加方法、实现继承以及注意潜在的陷阱。

版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权本站发表,未经许可,不得转载。

作者文章
热门
最新文章
标签列表