JavaScript 原型与原型链详情

JavaScript 原型与原型链详情

在 JavaScript 中,每个对象都拥有一个原型(prototype)属性。原型是一个对象,它包含了创建当前对象的构造函数的原型。当你访问一个对象的属性时,JavaScript 引擎会先在该对象本身中查找是否有这个属性,如果没有,它会去该对象原型(也就是构造函数的原型)中查找是否有这个属性,如果还没有,就会继续在原型的原型中查找,直到找到该属性或者到达 Object 的原型为止。这种属性查找的链式结构就是原型链。

构造函数与实例

在 JavaScript 中,每个函数既可以作为普通函数调用,也可以作为构造函数使用。当函数作为构造函数使用时,它们会返回一个新创建的对象。我们可以使用 new 运算符来创建对象,例如:

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

var person1 = new Person('小明', 18);
var person2 = new Person('小红', 20);
console.log(person1.name); // 小明
console.log(person2.age); // 20

在上面的代码中,我们通过构造函数 Person 创建了两个对象 person1 和 person2。由于 person1 和 person2 都是使用 Person 构造函数创建的,所以它们都具有 name 和 age 两个属性。

原型和原型链

当我们使用构造函数创建对象时,JavaScript 引擎会自动为这个对象创建一个原型属性 prototype,它指向该对象的构造函数的原型属性。假设我们现在有两个对象 person1 和 person2,它们都是使用 Person 构造函数创建的,那么它们的原型属性 prototype 就会指向如下对象:

Person.prototype = {
  constructor: Person,
  sayName: function() {
    console.log(this.name);
  }
};

所以,当我们在 person1 或者 person2 对象中查找 name 属性时,如果该对象本身没有这个属性的话,JavaScript 引擎就会在该对象原型(也就是 Person.prototype 对象)中查找是否有该属性。如果该属性在 Person.prototype 对象中存在,JavaScript 引擎就会把该属性返回给我们。

如果 person1 或者 person2 对象中仍然没有找到该属性,JavaScript 引擎就会在 Person.prototype 的原型中继续查找。由于 Person.prototype 是一个对象,它也有一个原型属性,这个原型属性指向它的构造函数 Object.prototype。最后,如果在 Object.prototype 中还没有找到该属性,JavaScript 引擎就会返回 undefined。

实例与原型的关系

我们知道,当我们使用 new 运算符创建对象时,JavaScript 引擎会为该对象创建一个原型属性 prototype,这个属性与构造函数的原型属性相等(Person.prototype)。同时,JavaScript 引擎还会把该对象的 proto 属性指向该对象原型属性(也就是 Person.prototype)。例如:

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

var person1 = new Person('小明', 18);

console.log(person1.__proto__ === Person.prototype); // true

上面的代码中,我们创建了一个 Person 对象 person1,然后我们可以通过 person1.proto 访问该对象的原型属性。由于 person1 是通过 Person 构造函数创建的,所以 person1.proto 指向的就是 Person.prototype。

同时,我们也知道,当我们在 person1 对象中查找 name 属性时,如果该对象本身没有这个属性的话,JavaScript 引擎就会在该对象原型(也就是 Person.prototype 对象)中查找是否有该属性。

示例

以下是使用构造函数创建对象、原型和原型链的两个示例:

示例一

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

Animal.prototype.eat = function() {
  console.log(this.name + '正在吃东西');
};

function Cat(name) {
  Animal.call(this, name);
  this.type = 'cat';
}

Cat.prototype = Object.create(Animal.prototype, {
  constructor: {
    value: Cat,
    enumerable: false,
    writable: true,
    configurable: true
  }
});

Cat.prototype.miao = function() {
  console.log(this.name + '正在喵喵叫');
};

var cat = new Cat('小猫');
cat.miao(); // 小猫正在喵喵叫
cat.eat(); // 小猫正在吃东西

在上面的代码中,我们定义了两个构造函数 Animal 和 Cat。Animal 构造函数用于创建动物对象,Cat 构造函数用于创建猫对象。我们通过 Object.create 方法将 Cat 的原型属性指向了 Animal 的原型属性,这样 Cat 就继承了 Animal 的所有属性和方法。

Cat 构造函数有一个 miao 方法,用于输出猫正在喵喵叫的信息。Animal 构造函数有一个 eat 方法,用于输出动物正在吃东西的信息。我们通过 Cat 对象 cat 调用 miao 和 eat 方法,发现它们都能正常输出信息。

示例二

function Car(name, price) {
  this.name = name;
  this.price = price;
}

Car.prototype.run = function() {
  console.log(this.name + '正在行驶');
};

function Audi(name, price) {
  Car.call(this, name, price);
  this.type = 'SUV';
}

Audi.prototype = new Car();

var audi = new Audi('Audi Q5', '50万');
audi.run(); // Audi Q5正在行驶
console.log(audi.price); // 50万

在上面的代码中,我们定义了两个构造函数 Car 和 Audi。Car 构造函数用于创建汽车对象,Audi 构造函数用于创建奥迪对象。

我们通过 Car.call(this, name, price) 将 Audi 构造函数的作用域指向了 Car,这样我们就可以在 Audi 对象中调用 Car 构造函数中的属性和方法。

接下来,我们通过 Audi.prototype = new Car() 将 Audi 对象的原型指向了 Car 对象。这样一来,Audi 就继承了 Car 的所有属性和方法。

最后,我们创建了一个 Audi 对象 audi,并通过 audi.run() 方法输出 Audi Q5 正在行驶的信息。我们还通过 console.log(audi.price) 输出了 Audi Q5 的价格。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript 原型与原型链详情 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • sgtool.exe应用程序错误的解决方法

    解决“sgtool.exe应用程序错误”的方法 当你执行sgtool.exe文件时,可能会出现“应用程序无法正常启动,错误0xc000007b”的错误提示。这是由于操作系统无法正确加载所需的系统文件,通常是由于程序和操作系统之间的版本不兼容或系统文件损坏导致的,可以通过以下方法解决: 方法一:更新操作系统 如果您的操作系统不是最新版本,则必须更新您的系统以解…

    other 2023年6月25日
    00
  • Android Tablayout 自定义Tab布局的使用案例

    Android Tablayout 自定义Tab布局的使用案例 Tablayout是Android Material Design库中的一部分,它提供了一个用于展示多个页面的标签栏,很多应用程序都使用它来实现这个功能。默认情况下,Tablayout会使用系统提供的样式来展示标签。但是有时候我们可能需要自定义Tab布局,来满足一些特殊的需求。 本文将介绍如何使…

    other 2023年6月25日
    00
  • k8s 中的 service 如何找到绑定的 Pod 及实现 Pod 负载均衡的方法

    为了实现Pod的负载均衡,Kubernetes中的服务(Service)控制器可以通过按照服务标签匹配的方式,直接查找到绑定的Pod。下面来详细讲解k8s服务如何找到绑定的Pod以及实现Pod负载均衡的方法。 1.服务如何找到绑定的Pod Kubernetes服务控制器根据其服务标签选择器(Label Selector)中定义的标签选择器,找到所有符合选择器…

    other 2023年6月27日
    00
  • lwm2m协议

    lwm2m协议 简介 lwm2m(Lightweight M2M)协议是一种针对IoT设备和传感器的轻量级管理协议,其目的是为了实现设备的远程监测、配置、控制和固件更新。lwm2m协议的设计目标是可扩展性、安全性和非常低的通信开销。该协议基于CoAP(Constrained Application Protocol)协议,使用RESTful API接口实现对…

    其他 2023年3月29日
    00
  • js控制台不同的打印方式

    JavaScript控制台不同的打印方式 在JavaScript开发中,控制台是一个非常有用的工具,可以用来调试代码和输出信息。控制台提供了多种印方式,本文将介绍控制台的不同打印方式,包括console.log()、console.warn()、console.error()和console.table()。在介绍每种方式时,将提供至少两个示例说明。 con…

    other 2023年5月9日
    00
  • Windows下使用virtualenv创建虚拟环境的方式(两种)

    Windows下使用virtualenv创建虚拟环境的方式 在Windows操作系统下,我们可以使用virtualenv来创建虚拟环境,使得我们可以方便地在同一台机器上使用不同版本的Python以及不同的包集合,而不会互相干扰。本文将详细介绍两种使用virtualenv创建虚拟环境的方法。 方法一:使用pip安装virtualenv 步骤1:安装pip 在官…

    other 2023年6月27日
    00
  • 详解Android开发中Fragment的使用

    详解Android开发中Fragment的使用 在Android应用的开发中,Fragment是一个可重用的界面模块,它能够独立的存在于Activity中,并可以复用。本文中将会详细介绍Fragment的使用,包括如何在Activity中添加Fragment、Fragment的生命周期、Fragment之间的通信以及Fragment与Activity之间的通…

    other 2023年6月27日
    00
  • 从零开始搭建一个react项目开发

    以下是从零开始搭建一个React项目的完整攻略: 步骤一:创建React项目 你可以使用create-react-app来创建一个新的React项目。create-react-app是一个友好的命令行工具,它可以创建一个可用的React项目,并自动生成所需的配置文件。 npx create-react-app my-app cd my-app npm sta…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部