tutorials.de Buch-Aktion 05/2012
  • Kleines Beispiel zu Dynamic Proxys mit Javascript

    Hier mal ein kleines Beispiel wie einfach man mit Java Script ein bestehendes Objekt mit einem Stellvertreter Objekt (Proxy) wrappen kann um so zusätzliche Aktionen rund um den Methodenaufruf (davor, danach, oder gar anstatt) durchführen zu können.



    Code javascript:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>JavaScript Proxy Example</title>
            <script>
              
                //Proxy Factory
                var proxyFactory = {
                    createProxy: function(target, invocationHandler){
                        var proxy = {};
                        for (var key in target) {
                            if (typeof target[key] == "function") {
                                proxy[key] = function(){
                                    return invocationHandler(proxy, target, key, arguments);
                                };
                            }
                            /* we copy only functions
                        else { proxy[key] = target[key]; }
                            */
                        }
                        return proxy;
                    }
                };
                
                //Invocation Handler
                function handle(proxy, target, method, args){
                    alert("calling: " + method + " with args: " + args);
                    var result = target[method].apply(target, args);
                    return result;
                };
     
                //Service
                var service = {
                    operation1: function(arg1, arg2){
                        return "arg1:" + arg1 + " arg2:" + arg2;
                    }
                };
                
                var serviceProxy = proxyFactory.createProxy(service, handle);
                
                alert(serviceProxy.operation1("aaa", 3));
                
            </script>
        </head>
        <body>
        </body>
    </html>

    Gruß Tom
     


    Kommentare 2 Kommentare
    1. Avatar von Konstantin Denerz
      Konstantin Denerz -
      Hallo Thomas,

      wenn du dein Beispiel so erweiterst, dass der Service mehrere Operationen hat und du statt alert, die console für das Logging verwendest, dann funktioniert dein Beispiel nicht korrekt. Es wird immer die letzte Operation sein, die durch den Invocation Handler aufgerufen wird.
      Um es so zum Laufen zu kriegen, wie es gedacht war, müsste man die Variablen wie Operationsname (key) in einen eigenen Scope packen, da sonst die Referenz auf die letzte Zuweisung zeigt.

      So sieht die Ausgabe meines Tests aus:
      Code :
      1
      2
      3
      
      test2.html:28calling: operation2 with args: [object Arguments]
      test2.html:44op2
      test2.html:52arg1:aaa arg2:3

      Der Code für den Test:
      HTML-Code:
      <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
      <html>
          <head>
              <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
              <title>JavaScript Proxy Example</title>
              <script>
      
                  //Proxy Factory
                  var proxyFactory = {
                      createProxy: function(target, invocationHandler){
                          var proxy = {};
                          for (var key in target) {
                              if (typeof target[key] == "function") {
                                  proxy[key] = function(){
                                      return invocationHandler(proxy, target, key, arguments);
                                  };
                              }
                              /* we copy only functions
                          else { proxy[key] = target[key]; }
                              */
                          }
                          return proxy;
                      }
                  };
      
                  //Invocation Handler
                  function handle(proxy, target, method, args){
                      console.log("calling: " + method + " with args: " + args);
                      var result = target[method].apply(target, args);
                      return result;
                  };
      
                  //Service
                  var service = {
                      operation1: function(arg1, arg2){
                          console.log("op1");
                          return "arg1:" + arg1 + " arg2:" + arg2;
                      },
                      operation3: function(arg1, arg2){
                          console.log("op3");
                          return "arg1:" + arg1 + " arg2:" + arg2;
                      },
                      operation2: function(arg1, arg2){
                          console.log("op2");
                          return "arg1:" + arg1 + " arg2:" + arg2;
                      }
      
                  };
      
                  var serviceProxy = proxyFactory.createProxy(service, handle);
      
                  console.log(serviceProxy.operation1("aaa", 3));
      
              </script>
          </head>
          <body>
          </body>
      </html>

      Und hier der Lösungsvorschlag:

      HTML-Code:
      <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
      <html>
      <head>
          <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
          <title>JavaScript Proxy Example</title>
          <script>
      
              //Proxy Factory
              var proxyFactory = {
                  createProxy: function(target, invocationHandler) {
                      var proxy = {};
                      for (var key in target) {
                          if (typeof target[key] == "function") {
                              /* put variables in a new scope */
                              function createPlaceHolder(proxy, target, key) {
                                  proxy[key] = function() {
                                      return invocationHandler(proxy, target, key, arguments);
                                  };
                              }
      
                              createPlaceHolder(proxy, target, key);
                          }
                          /* we copy only functions
                           else { proxy[key] = target[key]; }
                           */
                      }
                      return proxy;
                  }
              };
      
              //Invocation Handler
              function handle(proxy, target, method, args) {
                  console.log("calling: " + method + " with args: " + args);
                  var result = target[method].apply(target, args);
                  return result;
              }
              ;
      
              //Service
              var service = {
                  operation1: function(arg1, arg2) {
                      console.log("op1");
                      return "arg1:" + arg1 + " arg2:" + arg2;
                  },
                  operation3: function(arg1, arg2) {
                      console.log("op3");
                      return "arg1:" + arg1 + " arg2:" + arg2;
                  },
                  operation2: function(arg1, arg2) {
                      console.log("op2");
                      return "arg1:" + arg1 + " arg2:" + arg2;
                  }
      
              };
      
              var serviceProxy = proxyFactory.createProxy(service, handle);
      
              console.log(serviceProxy.operation1("aaa", 3));
      
          </script>
      </head>
      <body>
      </body>
      </html>

      So sieht dann die Ausgabe aus:
      Code :
      1
      2
      3
      
      calling: operation1 with args: [object Arguments]
      test2.html:42op1
      test2.html:58arg1:aaa arg2:3

      Viele Grüße,

      Konstantin
    1. Avatar von Thomas Darimont
      Thomas Darimont -
      Hallo Konstantin,

      danke für den Tipp

      Du hast recht hier braucht man einen Scope damit die Variablen im Kontext gecaptured werden.

      Ich würde hier allerdings nur eine anonyme-Function für das scoping verwenden:
      Code javascript:
      1
      2
      3
      4
      5
      6
      7
      
      if (typeof target[key] == "function") {
         (function(key){
            proxy[key] = function(){
               return invocationHandler(proxy, target, key, arguments);
            };
         })(key);
      }

      Code javascript:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      
      <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
      <html>
          <head>
              <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
              <title>JavaScript Proxy Example</title>
              <script>
                
                  //Proxy Factory
                  var proxyFactory = {
                      createProxy: function(target, invocationHandler){
                          var proxy = {};
                          for (var key in target) {
                              if (typeof target[key] == "function") {
                                  (function(key){
                                      proxy[key] = function(){
                                          return invocationHandler(proxy, target, key, arguments);
                                      };
                                  })(key);
                              }
                              /* we copy only functions
                          else { proxy[key] = target[key]; }
                              */
                          }
                          return proxy;
                      }
                  };
                  
                  //Invocation Handler
                  function handle(proxy, target, method, args){
                      console.log("calling: " + method + " with args: " + args);
                      var result = target[method].apply(target, args);
                      return result;
                  };
       
                  //Service
                  var service = {
                      operation1: function(arg1, arg2){
                          return "op1 arg1:" + arg1 + " arg2:" + arg2;
                      },
                      operation2: function(arg1, arg2){
                          return "op2 arg1:" + arg1 + " arg2:" + arg2;
                      },
                      operation3: function(arg1, arg2){
                          return "op3 arg1:" + arg1 + " arg2:" + arg2;
                      }
                  };
                  
                  var serviceProxy = proxyFactory.createProxy(service, handle);
                  
                  console.log(serviceProxy.operation1("aaa", 3));
                  console.log(serviceProxy.operation3("ccc", 4));
                  
              </script>
          </head>
          <body>
          </body>
      </html

      Gruß Tom
    Kommentare Kommentar schreiben

    Klicke hier, um dich anzumelden

    Welche Farbe hat eine reife Zitrone?