Maison  >  Article  >  interface Web  >  Résumé de 9 méthodes d'implémentation de l'héritage dans les compétences JavaScript_javascript

Résumé de 9 méthodes d'implémentation de l'héritage dans les compétences JavaScript_javascript

WBOY
WBOYoriginal
2016-05-16 15:58:301019parcourir

Contrairement aux langages de programmation basés sur des classes tels que C et Java, l'héritage en JavaScript est basé sur des prototypes. Dans le même temps, JavaScript étant un langage très flexible, il existe de nombreuses façons d’implémenter l’héritage.

Le premier concept de base concerne les constructeurs et les chaînes de prototypes. Le constructeur de l'objet parent s'appelle Parent, le constructeur de l'objet enfant s'appelle Child et les objets parent et enfant correspondants sont respectivement parent et enfant.

Il y a un attribut caché [[prototype]] (attention pas prototype) dans l'objet. Dans Chrome, il s'agit de __proto__, mais dans certains environnements, il est inaccessible. Lors de l'accès aux propriétés ou aux méthodes d'un objet, toutes les propriétés de l'objet seront recherchées en premier. Si elles ne sont pas trouvées, les propriétés de l'objet prototype seront recherchées étape par étape le long de la chaîne de prototypes selon [[prototype]] jusqu'à ce qu'elles soient trouvées. Sinon, retournez undéfini.

1. Héritage de la chaîne prototype :

La chaîne de prototypes est le moyen par défaut d'implémenter l'héritage en JavaScript. Si vous souhaitez qu'un objet enfant hérite de l'objet parent, le moyen le plus simple est de pointer l'attribut prototype du constructeur de l'objet enfant vers une instance de l'objet parent :

Copier le code Le code est le suivant :

fonction Parent() {}
fonction Enfant() {}
Enfant.prototype = nouveau Parent()

À l'heure actuelle, l'attribut prototype de Child a été réécrit et pointe vers un nouvel objet, mais l'attribut constructeur de ce nouvel objet ne pointe pas correctement vers Child. Le moteur JS ne terminera pas automatiquement ce travail pour nous, ce qui nous oblige à le faire manuellement. La propriété constructeur de l'objet prototype de Child renvoie à Child :
Copier le code Le code est le suivant :

Enfant.prototype.constructor = Enfant

Ce qui précède est le mécanisme d'héritage par défaut en JavaScript, qui migre les propriétés et les méthodes qui doivent être réutilisées vers l'objet prototype et définit les parties non réutilisables comme propriétés propres de l'objet. Cependant, cette méthode d'héritage nécessite une nouvelle instance comme propriété. objet prototype, qui est efficace. Il sera inférieur.

2. Héritage prototypique (chaîne non prototype) :

Afin d'éviter le problème de la création répétée d'instances d'objet prototype dans la méthode précédente, vous pouvez directement pointer le prototype du constructeur d'objet enfant vers le prototype du constructeur d'objet parent de cette manière, toutes les propriétés et méthodes de Parent. .prototype peut également être réutilisé. En même temps, il n'est pas nécessaire de créer à plusieurs reprises des instances d'objet prototype :
.

Copier le code Le code est le suivant :

Enfant.prototype = Parent.prototype
Enfant.prototype.constructor = Enfant

Mais nous savons qu'en JavaScript, les objets existent en tant que types référence. Cette méthode pointe en fait les pointeurs enregistrés dans Child.prototype et Parent.prototype vers le même objet. Par conséquent, lorsque nous voulons utiliser le prototype d'objet enfant si vous étendez certaines propriétés dans. Afin de continuer l'héritage plus tard, le prototype de l'objet parent sera également réécrit, car il n'y a toujours qu'une seule instance de l'objet prototype ici, ce qui est aussi le défaut de cette méthode d'héritage.

3. Héritage temporaire du constructeur :

Afin de résoudre le problème ci-dessus, vous pouvez utiliser un constructeur temporaire pour agir comme couche intermédiaire. Toutes les opérations sur le prototype de l'objet enfant sont effectuées sur l'instance du constructeur temporaire et n'affecteront pas le prototype de l'objet parent :

Copier le code Le code est le suivant :

var F = fonction() {}
F.prototype = Parent.prototype
Enfant.prototype = nouveau F()
Enfant.prototype.constructor = Enfant

Dans le même temps, afin d'accéder aux attributs du prototype de classe parent dans l'objet enfant, vous pouvez ajouter un attribut pointant vers le prototype de l'objet parent dans le constructeur de l'objet enfant, tel que uber. De cette manière, l'objet enfant peut. être accessible directement via child.constructor.uber à l'objet prototype parent.

Nous pouvons encapsuler le travail ci-dessus dans une fonction, et appeler cette fonction à l'avenir peut facilement implémenter cette méthode d'héritage :

Copier le code Le code est le suivant :

fonction étendre (Enfant, Parent) {
var F = fonction() {}
F.prototype = Parent.prototype
Enfant.prototype = nouveau F()
Enfant.prototype.constructor = Enfant
Enfant.uber = Parent.prototype
>

Ensuite, vous pouvez l'appeler comme ceci :
Copier le code Le code est le suivant :

étendre(Chien, Animal)

4. Copie d'attribut :

Cette méthode d'héritage ne modifie fondamentalement pas la relation de la chaîne de prototypes, mais copie directement tous les attributs de l'objet prototype parent vers le prototype de l'objet enfant. Bien entendu, la copie ici ne s'applique qu'aux types de données de base et aux types d'objet. ne prend en charge que le passage par référence.

Copier le code Le code est le suivant :

function extend2 (Enfant, Parent) {
var p = Parent.prototype
var c = Enfant.prototype
pour (var je dans p) {
         c[i] = p[i]
>
c.uber = p
>

Cette méthode reconstruit certains attributs du prototype, ce qui sera moins efficace lors de la construction d'objets, mais peut réduire la recherche de la chaîne de prototypes. Cependant, je pense personnellement que les avantages de cette méthode ne sont pas évidents.

5. Héritage entre objets :

En plus de la méthode d'héritage entre constructeurs, vous pouvez également hériter directement entre objets sans constructeurs. Autrement dit, copiez directement les attributs de l'objet, y compris la copie superficielle et la copie approfondie.

Copie superficielle :
Acceptez l'objet à hériter, créez en même temps un nouvel objet vide, copiez les propriétés de l'objet à hériter dans le nouvel objet et renvoyez le nouvel objet :

Copier le code Le code est le suivant :

fonction extendCopy(p) {
var c = {}
pour (var je dans p) {
         c[i] = p[i]
>
c.uber = p
Retour c
>

Une fois la copie terminée, les attributs qui doivent être réécrits dans le nouvel objet peuvent être réécrits manuellement.

Copie approfondie :
Le problème de la copie superficielle est également évident : elle ne peut pas copier les attributs du type d'objet mais ne peut transmettre que la référence. Pour résoudre ce problème, une copie profonde doit être utilisée. L'objectif de la copie profonde réside dans l'appel récursif de copie. Lorsque les propriétés du type d'objet sont détectées, l'objet ou le tableau correspondant est créé et les valeurs du type de base sont copiées une par une.

Copier le code Le code est le suivant :

fonction deepCopy(p, c) {
c = c || pour (var je dans p) {
Si (p.hasOwnProperty(i)) {
Si (typeof p[i] === 'objet') {
                                   c[i] = Array.isArray(p[i]) [] : {}
                 deepCopy(p[i], c[i])
               } autre {
c[je] = p[je]
            }
>
>
Retour c
>

Une méthode ES5 Array.isArray() est utilisée pour déterminer si le paramètre est un tableau. Les environnements qui n'implémentent pas cette méthode doivent encapsuler manuellement une cale.

Copier le code Le code est le suivant :
Array.isArray = fonction(p) {
Renvoie p instance de tableau
>

Cependant, les variables de tableau de différents frameworks ne peuvent pas être jugées à l'aide de l'opérateur instanceof, mais cette situation est relativement rare.

6. Héritage prototype :

A l'aide de l'objet parent, créez un nouvel objet prototypé par l'objet parent via le constructeur :


Copier le code Le code est le suivant :

function object(o) {
    var n
    function F() {}
    F.prototype = o
    n = new F()
    n.uber = o
    return n
}

這裡,直接將父物件設定為子物件的原型,ES5 中的 Object.create()方法就是這種實作方式。

7.原型繼承與屬性拷貝混合:

原型繼承方法中以傳入的父對象為原型建構子對象,同時還可以在父對象提供的屬性之外額外傳入需要拷貝屬性的對象:

複製程式碼 程式碼如下:

function ojbectPlus(o, stuff) {
    var n
    function F() {}
    F.prototype = o
    n = new F()
    n.uber = o

    for (var i in stuff) {
        n[i] = stuff[i]
    }
    return n
}


8.多重繼承:

這種方式不涉及原型鏈的操作,傳入多個需要拷貝屬性的對象,依序進行屬性的全拷貝:

複製程式碼 程式碼如下:

function multi() {
    var n = {}, stuff, i = 0,
        len = arguments.length
    for (i = 0; i         stuff = arguments[i]
        for (var key in stuff) {
            n[i] = stuff[i]
        }
    }
    return n
}

根據物件傳入的順序依序進行拷貝,也就是說,如果後傳入的物件包含和前面物件相同的屬性,後者將會覆寫前者。

9.構造器借用:

JavaScript中的call()和apply()方法非常好用,其改變方法執行上下文的功能在繼承的實作中也能發揮作用。所謂建構子借用是指在子物件建構器中藉用父物件的建構子對this進行操作:

複製程式碼 程式碼如下:

function Parent() {}
Parent.prototype.name = 'parent'

function Child() {
    Parent.apply(this, arguments)
}
var child = new Child()
console.log(child.name)


這種方式的最大優勢就是,在子物件的建構器中,是對子物件的自身屬性進行完全的重建,引用類型的變數也會產生一個新值而不是一個引用,所以對子物件的任何操作都不會影響父對象。

而這種方法的缺點在於,在子物件的建置過程中沒有使用過new操作符,因此子物件不會繼承父級原型物件上的任何屬性,在上面的程式碼中,child的name屬性將會是undefined。

要解決這個問題,可以再次手動將子物件建構器原型設為父物件的實例:

複製程式碼 程式碼如下:

Child.prototype = new Parent()

但這又會帶來另一個問題,即父物件的建構器會被呼叫兩次,一次是在父物件建構器借用過程中,另一次是在繼承原型過程中。

要解決這個問題,就要去掉一次父物件建構器的調用,建構器借用不能省略,那麼只能去掉後一次調用,實現繼承原型的另一方法就是迭代複製:

複製程式碼 程式碼如下:

extend2(Child, Parent)

使用之前實作的extend2()方法即可。
Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn