Maison  >  Article  >  interface Web  >  Une introduction à la méthode d'implémentation de l'héritage dans les prototypes JavaScript

Une introduction à la méthode d'implémentation de l'héritage dans les prototypes JavaScript

青灯夜游
青灯夜游avant
2020-11-19 18:10:303482parcourir

Une introduction à la méthode d'implémentation de l'héritage dans les prototypes JavaScript

Dans cet article, nous discuterons des prototypes et de la façon de les utiliser pour l'héritage dans JS. Nous verrons également en quoi les méthodes prototypes diffèrent de l'héritage basé sur les classes.

Héritage

L'héritage est une caractéristique distinctive des langages de programmation qui a émergé avec l'introduction des langages de programmation orientés objet. La plupart de ces langages sont des langages basés sur des classes. Ici, la classe est comme un plan et l’objet est sa représentation. Autrement dit, pour créer un objet, nous devons d’abord créer une classe, puis nous pouvons créer n’importe quel nombre d’objets à partir d’une classe.

Imaginez que nous ayons une classe qui représente un smartphone. Cette classe a des fonctions comme les autres smartphones qui peuvent prendre des photos et disposer d'un positionnement GPS. Ce qui suit est une description d'une telle classe en utilisant C++ :

class SmartPhone {
  public:
  void captureImages() {}
}

SmartPhone x;
x.captureImages()

Nous créons une classe nommée SmartPhone, qui a une méthode nommée capturePictures pour prendre des photos.

Si nous avons besoin d'une classe iPhone capable de capturer des images et de certaines fonctionnalités spéciales telles que la numérisation d'identité faciale. Voici deux solutions possibles :

  • Réécrivez la fonctionnalité de capture d'image dans une nouvelle classe avec d'autres fonctionnalités courantes des smartphones, ainsi que des fonctionnalités spécifiques à l'iPhone. Mais cette approche nécessite plus de temps et d’efforts et introduit davantage de bugs.

  • Réutiliser des fonctions dans SmartPhone classes C'est le rôle de l'héritage, c'est aussi un moyen de réutiliser des fonctions dans d'autres classes/objets.

Voici comment nous héritons de la méthode SmartPhone de la classe capturePictures, implémentée en utilisant C++ comme suit :

class Iphone: public SmartPhone {
  public:
  void faceIDScan() {}
}

Iphone x

x.faceIDScan()

x.captureImages()

Ce qui précède est un exemple d'héritage simple. Cependant, cela montre que l'héritage nous permet de réutiliser le code d'une manière qui rend le programme résultant moins sujet aux erreurs et prend moins de temps à développer.

Voici quelques informations importantes sur les classes :

  • La classe qui hérite de la fonctionnalité est appelée une sous-classe
  • La classe héritée est appelée la classe parent
  • 🎜>
  • Une classe peut hériter de plusieurs classes en même temps
  • Nous pouvons avoir plusieurs niveaux d'héritage. Par exemple, la classe C hérite de la classe B et la classe B hérite de la classe A

Il est à noter que la classe elle-même ne fait rien. Aucun travail n'est réellement effectué tant que l'objet n'est pas créé à partir de la classe. Nous verrons pourquoi c'est différent de JavaScript.

Qu'est-ce qu'un prototype ?

[[Prototype]]En JS, tous les objets ont une propriété interne spéciale qui est essentiellement une référence à un autre objet. Cette référence dépend de la manière dont l'objet a été créé. Dans la spécification ECMAScript/JavaScript, il est représenté par

.

[[Prototype]]Puisque [[Prototype]] est lié à un objet, cet objet a sa propre référence

. C'est ainsi que vous construisez une chaîne prototype.

[[Prototype]]La chaîne

est la pierre angulaire de l'héritage en JS.

__proto__

Objet

[[Prototype]] Pour accéder au __proto__ d'un objet, la plupart des navigateurs fournissent l'attribut

. La méthode d'accès est la suivante :

obj.__proto__
Il est à noter que , cet attribut ne fait pas partie du standard ECMAScript, il est en réalité implémenté par le navigateur.

Obtention et définition de méthodes de prototype

__proto__En plus de l'attribut [[Prototype]], il existe également un moyen standard d'accéder à

 :

Object.getPrototypeOf(obj);
[[Prototype]] a une méthode similaire. Définir les propriétés :

Object.setPrototypeOf(obj, prototype);
[[Prototype]].prototype et

[[Prototype]].prototype de l'objet n'est rien de plus qu'une notation standard utilisée pour représenter le prototype d'un objet. De nombreux développeurs le confondent avec l'attribut .prototype, ce qui est complètement différent. Jetons un coup d'œil à l'attribut

.

newEn JS, il existe de nombreuses façons de créer des objets. Une façon est d'utiliser le constructeur, appelez-le en utilisant le mot-clé

comme ceci :

function SmartPhone(os) {
  this.os = os
}

let phone = new SmartPhone('Android')
phone Imprimez l'objet dans la console :

{
  os: "IPhone"
  __proto__{
    constructor: ƒ SmartPhone(os)
   __proto__: Object
  }
}
phone Maintenant, si nous voulons 🎜 >Il existe quelques méthodes sur l'objet, nous pouvons utiliser l'attribut .prototype sur la fonction, comme indiqué ci-dessous :
SmartPhone.prototype.isAndroid = function () {
  return this.os === 'Android' || 'android'
}

Lors de la création à nouveau de l'objet phone, imprimez l'objet phone comme suit :

{
  os: "Android"
  __proto__{
    isAndroid: ƒ()
    constructor: ƒ SmartPhone(os)
   __proto__: Object
  }
}

Nous pouvons voir la méthode [[Prototype]] dans le isAndroid() de l'objet.

En bref, une propriété .prototype est fondamentalement comme un plan d'un objet [[Prototype]] créé par un constructeur donné. Tout ce qui est déclaré dans une propriété/objet .prototype apparaîtra dans le [[Prototype]] de l'objet.

En fait, si vous comparez les SmartPhone.prototype 与téléphones [[Prototype]], vous constaterez qu'ils sont identiques :

console.log(Object.getPrototypeOf(phone) === SmartPhone.prototype);
// true

Il est à noter que nous pouvons également créer dans la méthode constructeur :

function ObjectA() {
  this.methodA = function () {}
}

let firstObj = new ObjectA()
console.log(firstObj)

这种方法的问题是当我们初始化一个新对象时。所有实例都有自己methodA的副本。相反,当我们在函数的原型上创建它时,对象的所有实例只共享方法的一个副本,显然使用原型的方式效率会过高。

当我们访问属性时这里发生了什么?

当我们访问一个属性以获取它时,会发生以下情况:

JS 引擎查找对象上的属性,如果找到了该属性,然后返回它。否则,JS 引擎将通过查看[[Prototype]]来检查对象的继承属性,如果找到该属性,则返回它,否则,它会查找 [[Prototype]][[Prototype]]。 找到属性或没有[[Prototype]]时,该链结束,这意味着我们已经到达原型链的末端。

当我们设置/创建属性时,JS 总是在对象本身上进行设置。 即使[[Prototype]]链上存在相同的属性,下面是一个例子:

function MyObject() {}
MyObject.prototype.propA = 10; // 在原型上创建属性

let myObject = new MyObject();
console.log(myObject.propA); // [[Prototype]]上的属性
// 10

myObject.propA = 20; // 对象的属性
console.log(myObject.propA);
// 20

在上面的示例中,我们创建了一个构造函数,该函数的[[Prototype]]上具有属性propA。 当我们尝试对其进行读取操作时,会在控制台中看到该值。 但是,当我们尝试在对象本身上设置相同的属性时;JS 使用给定值在对象上创建一个新属性。 现在,如果我们不能直接访问[[Prototype]]上的属性。

值得注意的是,普通对象的[[Prototype]]链的末尾是内置的Object.prototype。 这就是为什么大多数对象共享许多方法(例如toString())的原因。 因为它们实际上是在Object.prototype上定义的。

使用原型继承的各种方法

在 JS 中,无论我们如何创建对象,只有原型继承,但这些方式还有一些区别,来看看:

对象字面量

在JavaScript中创建对象的最简单方法是使用对象字面量:

let obj = {}

如果在浏览器的控制台中打印obj,我们将看到以下内容:

Une introduction à la méthode dimplémentation de lhéritage dans les prototypes JavaScript

基本上,所有用文字面量创建的对象都继承了Object.prototype的属性。

需要注意的是__proto__对象引用了创建它的构造函数。 在这种情况下,constructor属性指向Object构造函数。

使用对象构造函数

另一种不太常见的创建对象的方法是使用对象构造函数。JS 提供了一个名为Object的内置构造函数方法来创建对象。

let obj = new Object();

这种方法的结果与对象字面量的方式相同。它从Object.prototype继承属性。因为我们使用Object作为构造函数。

Object.create 方法

使用此辅助方法,我们可以创建一个带有[[Prototype]]的对象,如下所示:

let SmartPhone = {
  captureImages: function() {}
}

let Iphone = Object.create(SmartPhone)

Iphone.captureImages()

这是在 JS 中使用继承的最简单方法之一。猜猜我们如何在没有任何[[Prototype]]引用的情况下创建对象?

构造方法

与 JS 运行时提供的对象构造函数相似。 我们还可以创建自己的构造函数,以创建适合我们需求的对象,如下所示:

function SmartPhone(os) {
  this.os = os;
}

SmartPhone.prototype.isAndroid = function() {
  return this.os === 'Android';
};

SmartPhone.prototype.isIOS = function() {
  return this.os === 'iOS';
};

现在,我们想创建一个iPhone类,它应该有'iOS'作为它 os 属性的值。它还应该有faceIDScan方法。

首先,我们必须创建一个Iphone构造函数,在其中,我们应该调用SmartPhone构造函数,如下所示:

function Iphone() {
   SmartPhone.call(this, 'iOS');
}

这会将Iphone构造函数中的this.os属性设置为’iOS‘

之所以调用SmartPhone.call方法,是因为我们需要更改 this 值以引用Iphone。 这类似于在面向对象的世界中调用父级的构造函数。

接下来的事情是,我们必须从SmartPhone构造函数继承方法。 我们可以在此处使用Object.create朋友,如下所示:

Iphone.prototype = Object.create(SmartPhone.prototype);

现在,我们可以使用.prototypeIphone添加方法,如下所示:

Iphone.prototype.faceIDScan = function() {};

最后,我们可以使用Iphone创建一个对象,如下所示:

let x = new Iphone();

// calling inherited method
console.log(x.isIOS()):
// true

ES6 class

使用ES6,整个过程非常简单。 我们可以创建类(它们与C ++或其他任何基于类的语言中的类不同,只是在原型继承之上的语法糖),然后从其他类派生新的类。

下面是我们如何在ES6中创建类:

class SmartPhone {
  constructor(os) {
    this.os = os;
  }
  isAndroid() {
    return this.os === 'Android';
  }
  isIos() {
    return this.os === 'iOS';
  }
};

现在,我们可以创建一个派生自SmartPhone的新类,如下所示:

class Iphone extends SmartPhone {
   constructor() {
     super.call('iOS');
   }
   faceIDScan() {}
}

我们不是调用SmartPhone.call,而是调用super.call。 在内部,JavaScript引擎会自动为我们执行此操作。

最后,我们可以使用Iphone创建一个对象,如下所示

let x = new Iphone();

x.faceIDScan();

// calling inherited method
console.log(x.isIos()):
// true

该ES6示例与先前的构造方法示例相同。 但是阅读和理解起来要干净得多。

原文:https://javascript.info/prototype-inheritance

作者:Indermohan Sing

更多编程相关知识,请访问:编程课程!!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer