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.prototype。Object.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 中非常重要的特性,理解它们的工作原理可以帮助开发者更好地设计类和对象,实现代码复用和继承。通过本文的示例,我们了解了如何使用原型添加方法、实现继承以及注意潜在的陷阱。
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权本站发表,未经许可,不得转载。
开发学习网



