41 votes

Définir Setter / Getter pour une variable locale sans parenté: impossible?

Il y a quelques questions précédentes sur StackOverflow se demandant comment on va sur l'accès aux variables locales via la portée de la chaîne, comme si tu voulais faire référence à un local de variables à l'aide du support de la notation et une chaîne, vous auriez besoin de quelque chose comme __local__["varName"]. Jusqu'à présent je n'ai pas trouvé encore la hackiest méthode pour parvenir à cet objectif, et ne viens pas avec une méthode après des heures d'exploitation de tous les trucs que je connais.

Le but pour lui est de mettre en œuvre des getters/setters arbitraires, unparented variables. Objet.defineProperties ou __defineGet/Setter__ besoin d'un contexte pour être appelé. Pour les propriétés dans le global ou le contexte de la fenêtre que vous pouvez accomplir l'objectif de disposer d'un setter/getter pour les références directes à l'objet.

Object.defineProperty(this, "glob", {get: function(){return "direct access"})
console.log(glob); //"direct access"

Même dans mes tests avec une extension personnalisée j'ai compilé en une modification de Chrome qui s'exécute avant tout à la création de fenêtre où le contexte est le contexte global, et même d'essayer d'appeler this directement dans le contexte mondial se bloque mon programme, je peux sortir sans accroc:

Object.defineProperty(Object.prototype, "define", {
    value: function(name, descriptor){
        Object.defineProperty(this, name, descriptor);
    }
};
define("REALLYglobal", {get: function(){ return "above window context"; }});

Et puis, il est disponible dans toutes les images créées plus tard mondial acheminé à travers le spécifiée getter/setter. Le vieux - __defineGet/Setter__ travaille aussi dans ce contexte, sans préciser ce que d'appeler (ne fonctionne pas dans Firefox, cependant, la méthode ci-dessus ne).

Donc, fondamentalement, il est possible de définir des get/set gardes pour toute variable sur un objet, y compris la fenêtre/contexte mondial avec appel direct à l'objet (vous n'avez pas besoin d' window.propname, juste propname). C'est le problème avec le fait d'être incapable de référence unparented d'étendue variables, étant le seul type qui peut être accessible portée mais n'ont pas adressable conteneur. Bien sûr, ils sont aussi les plus couramment utilisées il n'est donc pas un cas limite. Ce problème dépasse aussi la mise en œuvre actuelle de Procurations dans l'ES6/Harmonie puisque c'est un problème avec le fait d'être incapable de répondre à un local de l'objet conteneur avec la syntaxe du langage.

La raison pour laquelle je veux être capable de faire cela, c'est que c'est la seule barrière à autoriser la surcharge de plus de maths opérateurs pour l'utilisation dans des objets complexes comme les tableaux et les tables de hachage et d'en déduire un complexe résultant de la valeur. J'ai besoin d'être en mesure de s'accrocher dans le setter dans les cas où une valeur est définie sur un type d'objet que j'ai mis en place pour la surcharge. Pas de problème si l'objet peut être global ou peut être contenue dans un objet parent, ce qui est probablement ce que je vais juste aller avec. Il est toujours utile avec a.myObject, mais le but est de le rendre aussi transparente utilisable que possible.

Non seulement cela, mais il avait juste être vraiment utile d'être en mesure d'accomplir quelque chose comme ceci:

var point3d = function(){
    var x, y, z;
    return {
        get: function(){ return [x, y, z]; },
        set: function(vals){ x=vals[0]; y=vals[1]; z=vals[2]; }
    };
};

(Qui est similaire à ES6 de déstructuration, mais a des applications plus générales pour la mise en œuvre des fonctionnalités attachées à l'obtention de réglage/et pas seulement le transport de valeurs complexes). Même ce code de base échouer:

var x = {myname: "intercept valueOf and :set: to overload math ops!", index: 5};
x++; //x is now NaN if you don't implement a setter somehow

Je ne se soucient pas comment hacky la solution est, à ce stade, c'est juste une intense curiosité pour moi, s'il peut être accompli, même s'il faut supprimer toutes les meilleures pratiques qui existent. J'ai écrasé Firefox et Chrome une centaine de fois dans la poursuite de cette mesure en faisant des choses comme la redéfinition/interception/modifier Object.prototype.valueOf/toString, Function.prototype Function.prototype.constructor, Function.prototype.call/apply, arguments.callee.caller, etc. avec une récursion infinie erreurs et autres joyeusetés dans les tentatives de gréement contextes rétroactivement. La seule chose que je ai été en mesure de faire le travail emballage est fondamentalement toute l'histoire du eval et dynamiquement le code de la construction des morceaux, ce qui est un pont trop loin pour moi de l'utiliser réellement. Le seul autre à distance succès de la route à l'aide de with combiné avec la pré-définition de toutes les variables locales sur un conteneur, mais évidemment c'est très intrusif sur le dessus des problèmes avec l'utilisation de with.

7voto

benvie Points 6181

Cela est actuellement possible dans les environnements de serveurs proxy. Que serait node > 0.6 exécuter en tant qu' node --harmony_proxies ou >0.7 avec node --harmony. Chrome Canary (pas sûr si c'est de ça pour l'instant) dans about:flags au fond, expérimental javascript. Firefox a eu pendant un certain temps avec pas de drapeaux.

Donc, ce ne sera probablement pas de travail lors de l'ES6 devient de plus en plus officiel, mais il fonctionne à un point maintenant.

  var target = (function(){
    var handler = Proxy.create(Proxy.create({
      get: function(r, trap){
        return function(name,val,c,d){
          if (trap === 'get' || trap === 'set') {
            name = val;
            val = c;
          }
          console.log('"'+trap + '" invoked on property "'+name+'" ' + (val?' with value "'+val+'"':''));
          switch (trap) {
            case 'get': return target[name];
            case 'set': return target[name] = val;
            case 'has': return name in target;
            case 'delete': return delete target;
            case 'keys': return Object.keys(target);
            case 'hasOwn': return Object.hasOwnProperty.call(target, name);
            case 'getPropertyDescriptor':
            case 'getOwnPropertyDescriptor': return Object.getOwnPropertyDescriptor(target, name);
            case 'getPropertyNames':
            case 'getOwnPropertyNames': return Object.getOwnPropertyNames(target);
            case 'defineProperty': return Object.defineProperty(target, name, val);
          }
        }
      }
    }))

    var target = {
      x: 'stuff',
      f: { works: 'sure did' },
      z: ['overwritten?']
    };


    with (handler){
      var z = 'yes/no';
      if (x) {
        //x
      } else {
        x = true;
      }
      console.log(f.works);
      if (f.works) {
        f.works = true;
        delete f;
      }

    }
    return target
  })()
   // "getPropertyDescriptor" invoked on property "z" 
   // "getPropertyDescriptor" invoked on property "z" 
   // "getPropertyDescriptor" invoked on property "x" 
   // "get" invoked on property "x" 
   // "getPropertyDescriptor" invoked on property "console" 
   // "getPropertyDescriptor" invoked on property "f" 
   // "get" invoked on property "f" 
   // sure did
   // "getPropertyDescriptor" invoked on property "f" 
   // "get" invoked on property "f" 
   // "getPropertyDescriptor" invoked on property "f" 
   // "get" invoked on property "f" 
   // "getPropertyDescriptor" invoked on property "f" 

   target: { x: 'Stuff', f: { works: true },  z: ['overwritten?'] }

Frappé ou manquer et que vous devez prendre soin de ne pas exploser votre navigateur en regardant simplement un Proxy dans le débogueur. J'ai dû envelopper cette chose, d'une fermeture à garder le proxy de se retrouver dans la portée globale ou il s'est écrasé le cadre à chaque fois. Le Point est qu'il fonctionne dans une certaine mesure, où rien d'autre ne le fait.

6voto

kzh Points 5098

Il semble que la réponse soit non . Je recherche un comportement comme celui-ci depuis un bon moment. Je n'ai pas pu trouver de solution praticable. Cette question SO semble similaire. Python a le joli mot-clé locals .

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