Maison > Article > interface Web > Explication détaillée des compétences JavaScript orientées objet successoral_javascript
1. Mécanisme d'héritage d'objet
Cet exemple utilise UML pour très bien expliquer le mécanisme d'héritage.
La manière la plus simple d’illustrer le mécanisme d’héritage est d’utiliser un exemple classique de formes géométriques. En fait, il n’existe que deux types de formes géométriques, les ellipses (qui sont circulaires) et les polygones (qui possèdent un certain nombre de côtés). Un cercle est un type d’ellipse qui n’a qu’un seul foyer. Les triangles, les rectangles et les pentagones sont tous des types de polygones comportant un nombre variable de côtés. Un carré est une sorte de rectangle dont tous les côtés ont la même longueur. Cela constitue une relation d’héritage parfaite et explique bien le mécanisme d’héritage orienté objet.
Dans cet exemple, la forme est la classe de base de l'ellipse et du polygone (généralement, nous pouvons également l'appeler la classe parent, et toutes les classes en héritent). L'ellipse a des foyers, ce qui indique le nombre de foyers que possède l'ellipse. Circle hérite de l'ellipse, donc le cercle est une sous-classe de l'ellipse et l'ellipse est la superclasse du cercle. De même, les triangles, les rectangles et les pentagones sont tous des sous-classes de polygones, qui sont leur superclasse. Finalement, le carré hérite du rectangle.
Il est préférable d'utiliser un diagramme pour expliquer cette relation d'héritage, c'est là qu'intervient UML (Unified Modeling Language). L’une des principales utilisations d’UML est de représenter visuellement des relations d’objets complexes comme l’héritage. Le diagramme suivant est un diagramme UML expliquant la relation entre une forme et ses sous-classes :
En UML, chaque case représente une classe, décrite par le nom de la classe. Les segments de ligne situés au sommet des triangles, des rectangles et des pentagones se rejoignent pour pointer vers des formes, indiquant que ces classes héritent de formes. De même, la flèche pointant du carré vers le rectangle illustre la relation d'héritage entre eux.
2. Implémentation du mécanisme d'héritage ECMAScript
Pour implémenter le mécanisme d'héritage avec ECMAScript, vous pouvez commencer par la classe de base dont vous souhaitez hériter. Toutes les classes définies par le développeur peuvent servir de classes de base. Pour des raisons de sécurité, les classes natives et hôtes ne peuvent pas servir de classes de base. Cela empêche l'accès public au code compilé au niveau du navigateur qui pourrait être utilisé pour des attaques malveillantes.
Après avoir sélectionné la classe de base, vous pouvez créer ses sous-classes. C'est à vous de décider si vous souhaitez utiliser ou non une classe de base. Parfois, vous souhaiterez peut-être créer une classe de base qui ne peut pas être utilisée directement, mais qui est uniquement utilisée pour fournir des fonctions communes aux sous-classes. Dans ce cas, la classe de base est considérée comme une classe abstraite. Bien qu'ECMAScript ne définisse pas les classes abstraites aussi strictement que d'autres langages, il crée parfois des classes dont l'utilisation n'est pas autorisée. Habituellement, nous appelons cette classe une classe abstraite.
La sous-classe créée héritera de toutes les propriétés et méthodes de la superclasse, y compris l'implémentation des constructeurs et des méthodes. N'oubliez pas que toutes les propriétés et méthodes sont publiques, les sous-classes peuvent donc accéder directement à ces méthodes. Les sous-classes peuvent également ajouter de nouvelles propriétés et méthodes qui ne figurent pas dans la superclasse, ou elles peuvent remplacer les propriétés et méthodes de la superclasse. Puisque JS n’est pas un langage orthodoxe orienté objet, certains noms doivent également être modifiés.
3. Méthodes d'héritage ECMAScript
Dans le langage ECMAScript, la classe héritée (classe de base) est appelée un supertype et la sous-classe (ou classe dérivée) est appelée un sous-type. Comme pour d’autres fonctionnalités, ECMAScript implémente l’héritage de plusieurs manières. En effet, le mécanisme d'héritage en JavaScript n'est pas explicitement spécifié, mais implémenté par imitation. Cela signifie que tous les détails de l'héritage ne sont pas entièrement gérés par l'interpréteur. En tant que développeur, vous avez le droit de décider de la méthode d’héritage qui vous convient le mieux. Voici quelques méthodes d’héritage spécifiques pour vous.
(1) Méthode de chaîne de prototypes
Cette forme d'héritage était à l'origine utilisée pour la chaîne de prototypes dans ECMAScript. Le billet de blog précédent a présenté la méthode prototype de création d’objets. Les chaînes de prototypes étendent cette approche pour implémenter le mécanisme d’héritage de manière intéressante. L'objet prototype est un modèle et les objets à instancier sont basés sur ce modèle. En résumé, toutes les propriétés et méthodes de l'objet prototype sont transmises à toutes les instances de cette classe. La chaîne de prototypes utilise cette fonctionnalité pour implémenter le mécanisme d'héritage. Regardons un exemple :
function A() {//超类型A中必须没有参数 this.color = "red"; this.showColor = function () { return this.color; }; }; function B() {//子类型B this.name = "John"; this.showName = function () { return this.name; }; }; B.prototype = new A();//子类型B继承了超类型A,通过原型,形成链条 var a = new A(); var b = new B(); document.write(a.showColor());//输出:blue document.write(b.showColor());//输出:red document.write(b.showName());//输出:John
Dans la chaîne de prototypes, l'opérateur instanceof fonctionne également de manière unique. Pour toutes les instances de B, instanceof renvoie vrai pour A et B. Il s'agit d'un outil extrêmement utile dans le monde faiblement typé d'ECMAScript, mais il ne peut pas être utilisé lors de l'usurpation d'identité d'objet. Par exemple :
var b = new B(); document.write(b instanceof A);//输出:true document.write(b instanceof B);//输出:true
使用原型链方式实现了继承,但是这种方式无法共享和子类型给超类型传递参数。我们可以借用构造函数方式(也就是对像冒充)的方式来解决这两个问题。
(2)对象冒充方式
对象冒充方式的其原理如下:构造函数使用this关键字给所有属性和方法赋值(即采用对象声明的构造函数方式)。因为构造函数只是一个函数,所以可使A构造函数成为B的方法,然后调用它。B就会收到A的构造函数中定义的属性和方法。例如,用下面的方式改写上面的例子创建对象A和B:
call()方法
function A(Color) {//创建超类型A this.color = Color; this.showColor = function () { return this.color; }; }; function B(Color,Name) {//创建子类型B A.call(this, Color);//对象冒充,给超类型传参 this.name = Name;//新添加的属性 this.showName = }; var a = new A("blue"); var b = new B("red", "John"); document.write(a.showColor());//输出:blue document.write(b.showColor());//输出:red document.write(b.showName());//输出:John
apply()方法
和上面call()方法唯一的区别就是在子类型B中的代码:
A.call(this,arguments);//对象冒充,给超类型传参
当然,只有超类型中的参数顺序与子类型中的参数顺序完全一致时才可以传递参数对象。如果不是,就必须创建一个单独的数组,按照正确的顺序放置参数。
使用对象冒充方式虽然解决了共享和传参的问题,但是没有原型,复用就更不可能了,所以我们组合上述的两种方式,即原型链方式和对象冒充的方式实现JS的继承。
(3)混合方式
这种继承方式使用构造函数定义类,并非使用任何原型。对象冒充的主要问题是必须使用构造函数方式,这不是最好的选择。不过如果使用原型链,就无法使用带参数的构造函数了。开发者如何选择呢?答案很简单,两者都用。由于这种混合方式使用了原型链,所以instanceof运算符仍能正确运行。
在上一篇文章,创建对象的最好方式是用构造函数定义属性,用原型定义方法。这种方式同样适用于继承机制,用对象冒充继承构造函数的属性,用原型链继承prototype对象的方法。用这两种方式重写前面的例子,代码如下:
function A(Color) { this.color = Color; }; A.prototype.showColor = function () { return this.color; }; function B(Color, Name) { A.call(this, Color);//对象冒充 this.name = Name; }; B.prototype = new A();//使用原型链继承 B.prototype.showName = function () { return this.name; }; var a = new A("blue"); var b = new B("red", "John"); document.write(a.showColor());//输出:blue document.write(b.showColor());//输出:red document.write(b.showName());//输出:John
继承的方式和创建对象的方式有一定的联系,推荐使用的继承方式还时原型链和对象冒充的混合方式。使用这种混合方式可以避免一些不必要的问题。
看这篇文章的时候,必须看一下前面的创建对象的方式:详解JavaScript基于面向对象之创建对象(1)和详解JavaScript基于面向对象之创建对象(2)。
以上就是本文的全部内容,希望对大家的学习有所帮助。