Maison > interface Web > js tutoriel > le corps du texte

Explication détaillée de l'injection de dépendances dans les compétences JavaScript_javascript

WBOY
Libérer: 2016-05-16 16:08:51
original
1068 Les gens l'ont consulté

Le monde de la programmation informatique est en fait un processus consistant à constamment abstraire des parties simples et à organiser ces abstractions. JavaScript ne fait pas exception. Lorsque nous utilisons JavaScript pour écrire des applications, utilisons-nous tous du code écrit par d'autres, comme certaines bibliothèques ou frameworks open source célèbres. À mesure que notre projet se développe, de plus en plus de modules sur lesquels nous devons nous appuyer deviennent de plus en plus importants. À l'heure actuelle, la manière d'organiser efficacement ces modules est devenue une question très importante. L'injection de dépendances résout le problème de l'organisation efficace des modules dépendants du code. Vous avez peut-être entendu le terme « injection de dépendances » dans certains frameworks ou bibliothèques, comme le célèbre framework front-end AngularJS. L'injection de dépendances est l'une des fonctionnalités très importantes. Cependant, l’injection de dépendances n’a rien de nouveau. Elle existe depuis longtemps dans d’autres langages de programmation tels que PHP. Dans le même temps, l’injection de dépendances n’est pas aussi compliquée qu’on l’imagine. Dans cet article, nous allons apprendre le concept d'injection de dépendances en JavaScript et expliquer de manière simple et conviviale comment écrire du code "style d'injection de dépendances".

Définition d'objectifs

Supposons que nous ayons maintenant deux modules. Le premier module est utilisé pour envoyer des requêtes Ajax, tandis que le deuxième module est utilisé comme routeur.

Copier le code Le code est le suivant :

var service = fonction() {
Retourner { nom : 'Service' };
>
var routeur = fonction() {
Retourner { nom : 'Routeur' };
>

A cette époque, nous avons écrit une fonction qui nécessite l'utilisation des deux modules mentionnés ci-dessus :
Copier le code Le code est le suivant :

var doSomething = fonction (autre) {
var s = service();
var r = routeur();
};

Ici, afin de rendre notre code plus intéressant, ce paramètre doit recevoir quelques paramètres supplémentaires. Bien sûr, nous pouvons complètement utiliser le code ci-dessus, mais le code ci-dessus est légèrement moins flexible sous tous ses aspects. Que se passe-t-il si le nom du module que nous devons utiliser change en ServiceXML ou ServiceJSON ? Ou que se passe-t-il si nous voulons utiliser de faux modules à des fins de tests. À ce stade, nous ne pouvons pas simplement modifier la fonction elle-même. Donc la première chose que nous devons faire est de passer le module dépendant en paramètre à la fonction, le code est le suivant :
Copier le code Le code est le suivant :

var doSomething = function (service, routeur, autre) {
var s = service();
var r = routeur();
};

Dans le code ci-dessus, nous transmettons exactement les modules dont nous avons besoin. Mais cela soulève un nouveau problème. Supposons que nous appelions la méthode doSomething dans les deux parties du code. À ce stade, que se passe-t-il si nous avons besoin d'une troisième dépendance. Pour le moment, ce n’est pas une bonne idée de modifier tout le code d’appel de fonction. Par conséquent, nous avons besoin d’un morceau de code pour nous aider à le faire. C’est le problème que l’injecteur de dépendances tente de résoudre. Nous pouvons désormais fixer nos objectifs :

1. Nous devrions pouvoir enregistrer les dépendances
2. L'injecteur de dépendances doit recevoir une fonction puis renvoyer une fonction capable d'obtenir les ressources requises
3. Le code ne doit pas être compliqué, mais doit être simple et convivial
4. L'injecteur de dépendances doit conserver la portée de la fonction transmise
5. La fonction transmise doit pouvoir recevoir des paramètres personnalisés, pas seulement les dépendances décrites

méthode requirejs/AMD

Peut-être avez-vous entendu parler du fameux requirejs, qui est une bibliothèque qui peut très bien résoudre les problèmes d'injection de dépendances :

Copier le code Le code est le suivant :

définir(['service', 'routeur'], fonction(service, routeur) { 
// ...
});

L'idée de requirejs est que nous devons d'abord décrire les modules requis, puis écrire nos propres fonctions. Parmi eux, l’ordre des paramètres est important. Supposons que nous devions écrire un module appelé injecteur capable d'implémenter une syntaxe similaire.
Copier le code Le code est le suivant :

var doSomething = injector.resolve(['service', 'router'], function(service, routeur, autre) {
Expect(service().name).to.be('Service');
Expect(router().name).to.be('Router');
Attendre(autre).to.be('Autre');
});
faireQuelquechose("Autre");

Avant de continuer, une chose qui doit être expliquée est que dans le corps de la fonction doSomething, nous utilisons la bibliothèque d'assertions expect.js pour garantir l'exactitude du code. Il y a ici quelque chose de similaire à l'idée du TDD (Test Driven Development).

Maintenant, nous commençons officiellement à écrire notre module d'injection. Tout d’abord, il doit s’agir d’un monolithe afin qu’il ait les mêmes fonctionnalités dans chaque partie de notre application.

Copier le code Le code est le suivant :

var injecteur = {
dépendances : {},
Registre : fonction (clé, valeur) {
This.dependencies[key] = valeur;
},
Résoudre : fonction (deps, func, scope) {

}
>


Cet objet est très simple, ne contenant que deux fonctions et une variable à des fins de stockage. Ce que nous devons faire est de vérifier le tableau deps, puis de rechercher la réponse dans la variable de dépendances. La partie restante consiste à utiliser la méthode .apply pour appeler la variable func que nous avons passée :
Copier le code Le code est le suivant :

résoudre : fonction (deps, func, scope) {
var arguments = [];
pour(var i=0; i            if(this.dependencies[d]) {
               args.push(this.dependencies[d]);
         } autre {
                throw new Error('Impossible de résoudre ' d);
>
>
Fonction de retour() {
           func.apply(scope || {}, args.concat(Array.prototype.slice.call(arguments, 0)));
                                             >

Si vous devez spécifier une portée, le code ci-dessus peut également s'exécuter normalement.

Dans le code ci-dessus, la fonction de Array.prototype.slice.call(arguments, 0) est de convertir la variable arguments en un véritable tableau. Jusqu’à présent, notre code réussit parfaitement le test. Mais le problème ici est que nous devons écrire les modules requis deux fois et que nous ne pouvons pas les organiser dans aucun ordre. Les paramètres supplémentaires viennent toujours après toutes les dépendances.

Méthode de réflexion

Selon l'explication de Wikipédia, la réflexion signifie qu'un objet peut modifier sa propre structure et son comportement pendant l'exécution du programme. En JavaScript, pour parler simplement, c'est la capacité de lire le code source d'un objet et d'analyser le code source. En revenant toujours à notre méthode doSomething, si vous appelez la méthode doSomething.toString(), vous pouvez obtenir la chaîne suivante :


Copier le code Le code est le suivant :
"fonction (service, routeur, autre) {
var s = service();
var r = routeur();
}"

De cette façon, tant que nous utilisons cette méthode, nous pouvons facilement obtenir les paramètres souhaités et, plus important encore, leurs noms. C'est également la méthode utilisée par AngularJS pour implémenter l'injection de dépendances. Dans le code AngularJS, on peut voir l'expression régulière suivante :

Copier le code Le code est le suivant :
/^fonctions*[^(]*(s*([^)]*))/m


Nous pouvons modifier la méthode de résolution avec le code ci-dessous :

Copier le code Le code est le suivant :

résoudre : fonction() {
var func, deps, scope, args = [], self = this;
func = arguments[0];
deps = func.toString().match(/^functions*[^(]*(s*([^)]*))/m)[1].replace(/ /g, '').split(' ,');
portée = arguments[1] || {};
Fonction de retour() {
      var a = Array.prototype.slice.call(arguments, 0);
pour(var i=0; i             var d = deps[i];
                 args.push(self.dependencies[d] && d != '' ? self.dependencies[d] : a.shift());
>
           func.apply(scope || {}, args);
                                             >

Nous utilisons l'expression régulière ci-dessus pour correspondre à la fonction que nous avons définie, et nous pouvons obtenir les résultats suivants :


Copier le code Le code est le suivant :
["fonction (service, routeur, autre)", "service, routeur, autre"]

À ce stade, nous n’avons besoin que du deuxième élément. Mais une fois que nous avons supprimé les espaces supplémentaires et divisé la chaîne par , nous obtenons le tableau deps. Le code suivant est la partie que nous avons modifiée :

Copier le code Le code est le suivant :
var a = Array.prototype.slice.call(arguments, 0);
...
args.push(self.dependencies[d] && d != '' ? self.dependencies[d] : a.shift());

Dans le code ci-dessus, nous parcourons les projets dépendants. S'il y a des projets manquants, s'il manque des parties dans les projets dépendants, nous les récupérons à partir de l'objet arguments. Si un tableau est vide, l'utilisation de la méthode shift renverra simplement undéfini sans générer d'erreur. Jusqu'à présent, la nouvelle version de l'injecteur ressemble à ceci :


Copier le code Le code est le suivant :
var doSomething = injector.resolve (function (service, autre, routeur) {
Expect(service().name).to.be('Service');
Expect(router().name).to.be('Router');
Attendre(autre).to.be('Autre');
});
faireQuelquechose("Autre");

Dans le code ci-dessus, nous sommes libres de mélanger l'ordre des dépendances.

Mais rien n’est parfait. Il existe un problème très sérieux avec l’injection de dépendances des méthodes réflexives. Lorsque le code est simplifié, des erreurs se produisent. En effet, au cours du processus de simplification du code, les noms des paramètres ont changé, ce qui entraînerait l'échec de la résolution des dépendances. Par exemple :


Copier le code Le code est le suivant :
var doSomething=function(e,t,n){var r=e();var i=t()}

Nous avons donc besoin de la solution suivante, tout comme dans AngularJS :

Copier le code Le code est le suivant :
var doSomething = injector.resolve(['service', 'router', function(service, routeur) {
}]);


Ceci est très similaire à la solution AMD que nous avons vue au début, nous pouvons donc intégrer les deux méthodes ci-dessus. Le code final est le suivant :
.
Copier le code Le code est le suivant :

var injecteur = {
    dépendances : {},
    registre : fonction (clé, valeur) {
        this.dependencies[key] = valeur;
    },
    résoudre : fonction() {
        var func, deps, scope, args = [], self = this;
        if(typeof arguments[0] === 'string') {
            func = arguments[1];
            deps = arguments[0].replace(/ /g, '').split(',');
            portée = arguments[2] || {};
        } autre {
            func = arguments[0];
            deps = func.toString().match(/^functions*[^(]*(s*([^)]*))/m)[1].replace(/ /g, '').split(' ,');
            portée = arguments[1] || {};
        >
        return function() {
            var a = Array.prototype.slice.call(arguments, 0);
            pour(var i=0; i                 var d = deps[i];
                args.push(self.dependencies[d] && d != '' ? self.dependencies[d] : a.shift());
            >
            func.apply(scope || {}, args);
        }       
    >
>

这一个版本的resolve方法可以接受两个或者三个参数。下面是一段测试代码:

复制代码 代码如下 :

var doSomething = injector.resolve('router,,service', function(a, b, c) {
    expect(a().name).to.be('Router');
    expect(b).to.be('Autre');
    expect(c().name).to.be('Service');
});
faireQuelquechose("Autre");

你可能注意到了两个逗号之间什么都没有,这并不是错误。这个空缺是留给Autre这个参数的。这就是我们控制参数顺序的方法。

结语

在上面的内容中,我们介绍了几种JavaScript中依赖注入的方法,希望本文能够帮助你开始使用依赖注入这个技巧,并且写出依赖注入风格的代码。

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal