JavaScript中的原型与原型链

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

什么是原型

在JavaScript中,每个对象都有一个特殊的内部属性[[Prototype]](在大多数浏览器中可以通过__proto__访问),这个属性指向另一个对象,也就是该对象的"原型"。

当我们访问一个对象的属性时,如果对象本身没有这个属性,JavaScript引擎会去它的原型对象上查找,如果原型对象上也没有,就会继续查找原型的原型,直到找到该属性或者到达原型链的末端(null)。

// 创建一个简单的对象const animal = {  eats: true};// 以animal为原型创建一个新对象const rabbit = {  jumps: true};rabbit.__proto__ = animal; // 设置rabbit的原型为animalconsole.log(rabbit.jumps); // true (来自rabbit自身)console.log(rabbit.eats);  // true (来自原型animal)

构造函数与原型

在JavaScript中,函数也是对象,每个函数都有一个prototype属性(注意不是__proto__)。当这个函数作为构造函数使用时(通过new调用),新创建的对象的[[Prototype]]会指向该函数的prototype对象。

function Person(name) {  this.name = name;}// 在Person的原型上添加方法Person.prototype.sayHello = function() {  console.log(`Hello, my name is ${this.name}`);};const john = new Person('John');john.sayHello(); // Hello, my name is John// john的原型是Person.prototypeconsole.log(john.__proto__ === Person.prototype); // true

原型链的查找机制

当访问一个对象的属性时,JavaScript会沿着原型链向上查找:

首先检查对象本身是否有该属性如果没有,检查对象的[[Prototype]](即原型对象)如果还没有,继续检查原型的原型直到找到该属性或者到达null
function Animal(name) {  this.name = name;}Animal.prototype.eats = true;function Rabbit(name) {  this.name = name;  this.jumps = true;}// 设置Rabbit.prototype的原型为Animal.prototypeRabbit.prototype = Object.create(Animal.prototype);const whiteRabbit = new Rabbit('White Rabbit');console.log(whiteRabbit.jumps); // true (来自Rabbit实例)console.log(whiteRabbit.eats);  // true (来自Animal.prototype)console.log(whiteRabbit.toString); // [function] (来自Object.prototype)// 原型链:// whiteRabbit -> Rabbit.prototype -> Animal.prototype -> Object.prototype -> null

现代JavaScript中的原型操作

虽然可以直接使用__proto__,但这不是标准特性。ES6提供了更标准的方法来操作原型:

// 获取原型const proto = Object.getPrototypeOf(rabbit);// 设置原型const newRabbit = Object.create(animal); // 创建新对象并以animal为原型// 检查是否是某对象的原型console.log(animal.isPrototypeOf(rabbit)); // true

原型链与继承

原型链是JavaScript实现继承的主要方式。通过设置构造函数的prototype属性,可以建立原型继承关系。

class Animal {  constructor(name) {    this.name = name;  }  eat() {    console.log(`${this.name} eats.`);  }}class Rabbit extends Animal {  constructor(name) {    super(name);  }  jump() {    console.log(`${this.name} jumps!`);  }}const bunny = new Rabbit('Bunny');bunny.eat();  // 继承自Animalbunny.jump(); // Rabbit自身的方法

虽然ES6引入了class语法,但它本质上仍然是基于原型的继承,只是提供了更简洁的语法。

理解原型和原型链是掌握JavaScript面向对象编程的关键,它解释了JavaScript中对象如何共享属性和方法,以及继承是如何实现的。

版权声明

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

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