Maison  >  Article  >  interface Web  >  Analyse complète des membres privés en js (avec code)

Analyse complète des membres privés en js (avec code)

不言
不言original
2018-08-14 11:09:521938parcourir

Ce que cet article vous apporte, c'est une analyse complète des membres privés en js (avec code). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Les déclarations de champs de classe pour JavaScript (déclarations de champs des classes JavaScript) sont maintenant entrées dans l'étape 3, qui comprend un élément qui préoccupe beaucoup les développeurs POO : les champs privés. Ce n’est pas pour rien que JavaScript n’a jamais eu de membres privés, cette proposition apporte donc de nouveaux défis à JavaScript. Mais en même temps, JavaScript envisageait déjà la question de la privatisation lors de la sortie d'ES2015, il n'est donc pas sans fondement pour implémenter des membres privés.

Fosse

Creusez d'abord une fosse - il s'agit d'un morceau de code JS, BusinessView doit faire deux choses, à savoir disposer le formulaire et la carte.

Représente que le préfixe _ est accepté comme étant privé
class BaseView {
    layout() {
        console.log("BaseView Layout");
    }
}

class BusinessView extends BaseView  {
    layout() {
        super.layout();
        this._layoutForm();
        this._layoutMap();
    }

    _layoutForm() {
        // ....
    }

    _layoutMap() {
        // ....
    }
}

Ensuite, en raison du développement de l'entreprise, il a été découvert que de nombreuses vues avaient des mises en page cartographiques. La méthode d'héritage est utilisée ici pour l'implémenter, de sorte que le contenu lié à la carte est extrait de BusinessView dans une classe de base appelée MapView :

class MapView extends BaseView {
    layout() {
        super.layout();
        this._layoutMap();
    }

    _layoutMap() {
        console.log("MapView layout map");
    }
}

class BusinessView extends MapView {
    layout() {
        super.layout();
        this._layoutForm();
        this._layoutMap();
    }

    _layoutForm() {
        // ....
    }

    _layoutMap() {
        console.log("BusinessView layout map");
    }
}

Les deux morceaux de code ci-dessus sont très typiques basés sur sur l'héritage. L'intention initiale de la POO est de s'attendre à ce que les classes de tous les niveaux puissent utiliser layout() pour effectuer des tâches de mise en page dont chaque niveau devrait être responsable. Mais il y a toujours un écart entre l'idéal et la réalité. Si vous l'exécutez en JavaScript, vous constaterez que BusinessView._layoutMap() est exécuté deux fois, tandis que MapView._layoutMap() ne l'est pas. Pourquoi ?

Fonction virtuelle

En JavaScript, si une méthode du même nom est définie dans les classes ancêtre et descendante, cette méthode dans la classe descendante sera appelée par défaut. Si vous souhaitez appeler la méthode du même nom dans la classe ancêtre, vous devez l'appeler via super. dans la classe descendante.

Ici vous pouvez analyser ce processus :

Lorsqu'une sous-classe crée un objet, les définitions de sa classe et de toutes les classes ancêtres ont été chargées. À ce moment-là,

  • appelle BusinessView.layout()

  • pour trouver super.layout() et commencer à appeler MapView.layout()

  • MapView.layout()this._layoutMap()
    • dans 🎜>
    • puis recherchez

      BusinessView_layoutMap()

      objet) > Trouvez-le et appelez-le
    Vous voyez, puisque
définit

, la chaîne prototype n'est pas du tout recherchée. Oui, il s'agit d'une limitation de la POO basée sur des relations prototypes. Si nous regardons le processus de traitement de C#, nous constaterons qu'il est différent BusinessView_layoutMap

    Appeler
  • BusinessView.layout()

  • Trouver
  • et commencer à appeler

    base.layout()MapView.layout()

  • est appelé dans

    MapView.layout()this._layoutMap()

    • Si oui, trouvez la dernière surcharge dans le fonction de sous-classe (override), appelez
    • Sinon, appelez directement
    • et recherchez
    • MapView_layoutMap() 🎜>

      Vérifier si la fonction virtuelle
    • Avez-vous remarqué la différence ? La clé est de déterminer la « fonction virtuelle ».
Mais qu’est-ce que cela a à voir avec les membres privés ? Parce que les fonctions privées ne sont certainement pas des fonctions virtuelles, en C#, si

est défini comme privé, alors

doit appeler

. _layoutMapMapView.layout()Le concept de fonctions virtuelles est un peu compliqué. Cependant, on peut simplement comprendre que si une méthode membre est déclarée comme fonction virtuelle, lorsqu'elle est appelée, elle suivra sa chaîne de fonctions virtuelles pour trouver la dernière surcharge à appeler. MapView._layoutMap()

Bien que le préfixe
soit convenu comme étant privé en JavaScript, il ne s'agit que d'un gentleman's Agreement, et il n'est toujours pas de nature privée. Un gentleman's Agreement est valable pour les personnes, mais l'ordinateur ne sait pas que vous avez cet accord... Cependant, si JavaScript implémente réellement des membres privés, alors l'ordinateur saura que
est une méthode privée et devra appeler la définition dans cette classe au lieu de rechercher la définition dans la sous-classe.

_Résoudre le problème actuel de la privatisation_layoutMap()

JavaScript n'a actuellement pas de membres privés, mais nous devons résoudre le problème des membres privés rapidement et efficacement, que devons-nous faire ? Bien sûr, il existe un moyen de le résoudre, en utilisant

et les fermetures.

Notez que la fermeture ici n'est pas un guide pour générer une fermeture dans une fonction, veuillez continuer la lecture Symbol

Tout d'abord, précisons clairement que nous examinerons cette question de privatisation dans un manière flexible - c'est-à-dire laisser les ancêtres Lorsqu'un appelant de classe appelle une méthode, il ne recherchera pas d'abord dans la sous-classe. Ce problème ne peut pas être résolu grammaticalement. JavaScript doit rechercher la méthode de spécification du nom à partir de l'instance spécifique vers l'arrière. Mais que se passe-t-il si le nom de la méthode est introuvable ?

之所以能找到,因为方法名是字符串。一个字符串在全局作用域内都表示着同样的意义。但是 ES2015 带来了 Symbol,它必须实例化,而且每次实例化出来一定代表着不同的标识 —— 如果我们将类定义在一个闭包中,在这个闭包中声明一个 Symbol,用它来作为私有成员的名称,问题就解决了,比如

const MapView = (() => {
    const _layoutMap = Symbol();

    return class MapView extends BaseView {
        layout() {
            super.layout();
            this[_layoutMap]();
        }

        [_layoutMap]() {
            console.log("MapView layout map");
        }
    }
})();

const BusinessView = (() => {
    const _layoutForm = Symbol();
    const _layoutMap = Symbol();

    return class BusinessView extends MapView {
        layout() {
            super.layout();
            this[_layoutForm]();
            this[_layoutMap]();
        }

        [_layoutForm]() {
            // ....
        }

        [_layoutMap]() {
            console.log("BusinessView layout map");
        }
    }
})();

而现代基于模块的定义,甚至连闭包都可以省了(模块系统会自动封闭作用域)

const _layoutMap = Symbol();

export class MapView extends BaseView {
    layout() {
        super.layout();
        this[_layoutMap]();
    }

    [_layoutMap]() {
        console.log("MapView layout map");
    }
}
const _layoutForm = Symbol();
const _layoutMap = Symbol();

export class BusinessView extends MapView {
    layout() {
        super.layout();
        this[_layoutForm]();
        this[_layoutMap]();
    }

    [_layoutForm]() {
        // ....
    }

    [_layoutMap]() {
        console.log("BusinessView layout map");
    }
}

改革过后的代码就可以按预期输出了:

BaseView Layout
MapView layout map
BusinessView layout map

相关推荐:

js中对执行上下文以及变量对象的解析

js中字符方法以及字符串操作方法的总结(附代码)

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:
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