原型链

75 阅读5分钟

原型链(Prototype Chain)

image.png

  • 原型链(Prototype Chain)是 JavaScript 中实现对象之间继承关系的一种机制。
  • 每个对象通过__proto__属性能访问到它的原型,原型也有它的原型
  • 当访问一个对象的属性和方法的时候,先在自身中寻找,如果没有,就会沿着__proto__这条链,往上(在它的原型中)寻找,一直找到最顶层Object.prototype为止,这样形成了一个原型对象的链条,即原型链。

示例:

// 构造函数
function Person(name) {
  this.name = name;
}

// 原型对象上定义的方法
Person.prototype.greet = function() {
  console.log("Hello, my name is " + this.name);
};

// 创建对象实例
var person = new Person("Alice");

// 访问对象实例的属性和方法
console.log(person.name); // 输出:Alice
person.greet(); // 输出:Hello, my name is Alice

  1. 在这个示例中,我们定义了一个构造函数 Person,并在 Person.prototype 上添加了 greet 方法。然后通过 new Person() 创建了一个 Person 的实例 person
  2. 当我们通过 person.name 访问 personname 属性时,JavaScript 引擎首先查找 person 对象本身,发现有 name 属性并返回。
  3. 当我们通过 person.greet() 调用 persongreet 方法时,JavaScript 引擎在 person 对象上找不到该方法,于是沿着原型链向上查找,找到了 Person.prototype 上定义的 greet 方法,并执行该方法。
  4. 这个示例展示了原型链的工作原理:当访问对象的属性或方法时,JavaScript 引擎会沿着原型链向上查找,直到找到或者到达原型链的顶端。这样就实现了对象之间的继承和共享。

数组的原型链

  • 数组也是一个对象,它由Array这个构造函数创建
const arr = [1, 2, 3]
arr.__proto__ === Array.prototype  // true
  • arr ---> Array.prototype ---> Object.prototype ---> null
  • proto 是一个桥梁

函数的原型链

  • 函数也是一个对象 它由Function构造函数创建
const fn = function(){} 
fn.__proto__ === Function.prototype  // true
  • fn ---> Function.prototype ---> Object.prototype ---> null

instanceof

作用:

  • instanceof 是 JavaScript 中的一个操作符,用于检查一个对象是否是某个构造函数(或其派生构造函数)的实例。它的作用是判断一个对象是否属于某个类或其派生类。
  • 用于检测A这个实例(对象)是不是B这个构造函数创建的,或者是不是B这个祖先构造函数创建的
  • instanceof 运算符可以用于判断对象的类型,特别是在涉及继承的情况下,可以方便地确定对象是否属于某个类或其派生类。

示例1:

function Person(name) {
  this.name = name;
}

var person = new Person("Alice");

console.log(person instanceof Person); // 输出:true

  • 在这个示例中,我们定义了构造函数 Person,然后通过 new Person() 创建了一个 Person 的实例 person
  • 通过 person instanceof Person,我们使用 instanceof 操作符检查 person 是否是 Person 构造函数的实例。由于 person 是通过 Person 构造函数创建的对象,所以 personPerson 的实例,person instanceof Person 返回 true
  • instanceof 运算符的语法是 object instanceof constructor,其中 object 是要检查的对象,constructor 是要检查的构造函数

示例2:

  • 展示了 instanceof 在继承关系中的应用:
function Animal() {}

function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

var dog = new Dog();

console.log(dog instanceof Animal); // 输出:true
console.log(dog instanceof Dog); // 输出:true

  • 在这个示例中,我们定义了构造函数 AnimalDog,并通过原型继承将 Dog 派生自 Animal。通过 dog instanceof Animal,我们检查 dog 是否是 Animal 构造函数的实例。由于 dog 的原型链上包含了 Animal.prototype,所以 dogAnimal 的实例,dog instanceof Animal 返回 true
  • 同样地,通过 dog instanceof Dog,我们检查 dog 是否是 Dog 构造函数的实例。由于 dog 是通过 Dog 构造函数创建的对象,所以 dogDog 的实例,dog instanceof Dog 返回 true

派生类

  • 在面向对象编程中,派生类(Derived Class)是基于已有类(称为基类或父类)创建的新类。派生类继承了基类的属性和方法,并且可以在其基础上添加新的属性和方法,或者修改继承的属性和方法。
  • 派生类通过继承基类的特性,实现了代码的重用和扩展。它可以从基类继承已有的行为,并添加新的行为或修改继承的行为,从而满足特定的需求。
  • 在 JavaScript 中,我们可以使用原型继承或类继承来创建派生类。原型继承通过设置对象的隐式原型(__proto__Object.setPrototypeOf())来实现,而类继承是 ES6 引入的基于 class 关键字的语法糖。

示例:

// 基类
function Animal(name) {
  this.name = name;
}

Animal.prototype.eat = function() {
  console.log(this.name + " is eating.");
};

// 派生类
function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  console.log(this.name + " is barking.");
};

// 创建派生类的实例
var dog = new Dog("Buddy", "Labrador");

dog.eat(); // 输出:Buddy is eating.
dog.bark(); // 输出:Buddy is barking.

  • 在这个示例中,Animal 是基类,Dog 是派生类。Dog 通过原型继承的方式继承了 Animal,并添加了自己的属性和方法。
  • 通过创建 Dog 的实例 dog,我们可以调用从基类继承的方法 eat(),以及派生类自己定义的方法 bark()
  • 需要注意的是,派生类在继承基类时,通常会执行基类的构造函数,以确保基类的属性正确地被初始化。在上述示例中,通过 Animal.call(this, name) 调用基类的构造函数,将 name 参数传递给基类的构造函数,以初始化派生类的 name 属性。
  • 派生类的概念使得在面向对象编程中可以通过继承和多态的机制来实现代码的重用和灵活性。它允许我们在已有类的基础上创建新的类,并根据需求进行扩展和修改。