5 votes

Protection d'un objet "API" Javascript global

J'ai actuellement une application Web qui fonctionne à partir d'une API globale basée sur le Javascript, et qui est initialisée comme suit :

var Api = {
    someVar: "test",
    someFunction: function() {
        return "foo";
    }
}

Cette API est partagée par de nombreux "Widgets" qui vivent dans l'application Web, et ils doivent tous fonctionner à partir de cette seule API. Api afin qu'ils puissent se transmettre des données.

AJAX est actuellement utilisé pour charger ces widgets, par exemple dans widgets/mywidget.html, et il est placé dans, disons, <div id='widget_<random number>'>...</div>

D'autres parties du code peuvent choisir d'ajouter plus de fonctionnalités à la fonction Api et c'est actuellement le cas :

Api.myExtension = {
    myNewFunction: function() {
        return "bar";
    }
}

Toutefois, ce type d'utilisation pose certains problèmes :

Premier problème : Que se passe-t-il si un widget (qui peut être fourni par des tiers) décide de cacher du code à l'intérieur, et fait quelque chose de similaire à Api = {} La Commission européenne a décidé de mettre en place un système d'alerte précoce, détruisant ainsi le système mondial d'alerte précoce. Api var tout continue, et briser l'ensemble de l'application ? Est-il possible de protéger cette Api d'être écrasée de l'extérieur ? Seule l'"extension" est autorisée (ajout de nouvelles choses), mais la "suppression/modification" ne l'est pas :

Api.foo = { test: "bar" } // allowed
Api.someVar = "changing the existing someVar"; // not allowed

Le code suivant se trouve "à l'intérieur" Api par exemple :

var Api = {
    Debug: {
        Messages = new Array,
        Write: function() {
            Api.Debug.Messages.push("test"); // allowed
        }
    }
}

Api.Debug.Messages.push("test 2"); // not allowed

Solutions probables auxquelles j'ai pensé :

  1. Supposons que nous utilisions simplement des cadres pour résoudre ce problème. Les Api sont désormais distincts l'un de l'autre. Cependant, il y a une surcharge supplémentaire lors du chargement de Api encore et encore si j'ai beaucoup de Widget et qu'ils ne peuvent plus communiquer avec l'"hôte" des widgets (la page où résident les cadres), par exemple, je peux vouloir dire à l'hôte d'afficher une notification : Api.Notify.Show("Test") mais il ne peut pas le faire parce que cette Api est complètement indépendant des autres instances et ne peut pas communiquer avec l'"hôte"

  2. En utilisant quelque chose comme une fonction "getter" et "setter" pour que l'Api soit lue et écrite. Je ne suis pas sûr de la façon de mettre cela en œuvre, donc toute aide sur la façon de mettre cela en œuvre est la bienvenue !

  3. Un mélange de 1/2 ?

2voto

BobS Points 804

Il n'y a pas de bon moyen d'éviter qu'un widget "tiers" écrase une variable globale. En règle générale, il incombe à la personne qui réalise l'application finale de s'assurer que les JavaScripts qu'elle utilise n'encombrent pas l'espace de noms global et n'entrent pas en conflit. La meilleure chose que vous puissiez faire dans ce sens est de donner à votre "Api" un nom agréable et unique.

Je pense que ce qui peut vous aider beaucoup est quelque chose comme le "revealing pattern", qui serait une façon de faire les "getters et setters" que vous avez mentionnés, plus d'autres choses si vous en avez besoin.

Un exemple simple et inutile serait le suivant :

var Api = (function () {
    // private variable
    var myArray = [];

    return {
        addItem: function (newItem) {
            myArray.push(newItem);
        },
        printItems: function () {
            console.log("lots if items");
        }
    };
})();

Api.addItem("Hello, world");
Api.extensionValue = 5;

Je pense que vous devriez délimiter clairement ce qui est partagé, ou les données "singleton", et garder ces éléments privés, comme avec myArray dans mon exemple.

2voto

Eran Medan Points 12234

Jetez un coup d'œil à

Object.freeze

Plus d'informations aquí

Voici un exemple de code tiré de la page de Mozilla :

var obj = {
  prop: function (){},
  foo: "bar"
};

// New properties may be added, existing properties may be changed or removed
obj.foo = "baz";
obj.lumpy = "woof";
delete obj.prop;

var o = Object.freeze(obj);

assert(Object.isFrozen(obj) === true);

// Now any changes will fail
obj.foo = "quux"; // silently does nothing
obj.quaxxor = "the friendly duck"; // silently doesn't add the property

// ...and in strict mode such attempts will throw TypeErrors
function fail(){
  "use strict";
  obj.foo = "sparky"; // throws a TypeError
  delete obj.quaxxor; // throws a TypeError
  obj.sparky = "arf"; // throws a TypeError
}

fail();

// Attempted changes through Object.defineProperty will also throw
Object.defineProperty(obj, "ohai", { value: 17 }); // throws a TypeError
Object.defineProperty(obj, "foo", { value: "eit" }); // throws a TypeError

Toutefois, la prise en charge par les navigateurs est encore partielle

EDIT Pour ce qui est de la réponse de Kernel James, elle est plus en rapport avec votre question (le gel protégera l'objet, mais pas sa réaffectation, mais la const. le fera).

2voto

Kernel James Points 1676

Faites-en un constant :

const Api = "hi";

Api = 0;

alert(Api); //"hi"

1voto

JCOC611 Points 5704

La seule façon (du moins celle à laquelle je pense) de protéger votre variable globale est d'empêcher les Widgets d'y avoir un accès direct. Cela peut être réalisé en utilisant des fonctions frames, comme vous l'avez suggéré. Vous devez créer un objet qui contient toutes les fonctions que les Widgets doivent pouvoir utiliser, et le passer à chaque Widget. Par exemple :

var Api = {
   widgetApi = {
      someFunction: function(){
          // ...
      }
   },
   addWidget:function(){
      var temp = this.widgetApi.constructor(); 

      for(var key in this.widgetApi)
         temp[key] = clone(this.widgetApi[key]);
      return temp;
   }
   // Include other variables that Widgets can't use
}

De cette manière, les widgets peuvent exécuter des fonctions et communiquer avec le système d'information. hôte ou la variable globale Api . Pour définir des variables, le widget modifie son objet privé, plutôt que l'objet global. Pour chaque frame (qui représente un Widget), vous devez initialiser ou créer une copie du widgetApi et probablement le stocker dans un tableau, de manière à ce qu'un objet instance d'un widget est stockée dans le fichier principal Api objet.

Par exemple, étant donné <iframe id="widget"></iframe>

Vous devez procéder comme suit :

var widget = document.getElementById("widget");
widget.contentWindow.Api = Api.addWidget();
widget.contentWindow.parent = null;
widget.contentWindow.top = null;

En outre, dans chaque cadre, vous devez définir le paramètre parent y top à null afin que les Widgets ne puissent pas accéder aux données du cadre principal. Je n'ai pas testé cette méthode depuis un moment, il y a donc peut-être des moyens de contourner le fait de mettre ces variables à null.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X