2010-02-15 9 views
39

Jest noSuchMethod cechą w niektórych implementacjach JavaScript (Rhino, SpiderMonkey)Czy istnieje odpowiednik funkcji __noSuchMethod__ dla właściwości lub sposób wdrożenia go w JS?

proxy = { 
    __noSuchMethod__: function(methodName, args){ 
     return "The " + methodName + " method isn't implemented yet. HINT: I accept cash and beer bribes" ; 
    }, 

    realMethod: function(){ 
    return "implemented" ; 
    } 
} 

js> proxy.realMethod() 
implemented 
js> proxy.newIPod() 
The newIPod method isn't implemented yet. HINT: I accept cash and beer bribes 
js> 

zastanawiałem się, czy istnieje sposób, aby zrobić coś podobnego dla właściwości? Chciałbym napisać klasy proxy, które mogą wywoływać zarówno właściwości, jak i metody.

+2

Czy kiedykolwiek znalazłeś rozwiązanie? –

+0

Pytanie było bardziej wywołane ciekawością niż potrzebą, próbowałem użyć Rhino jako silnika skryptowego dla aplikacji Java i polegało na tworzeniu js wrapperów dla obiektów hosta i ich metod - i właściwości. Ostatecznie przerzuciłem się na Clojure, ponieważ łatwiej było rozmawiać z Javą, chociaż tworzenie dynamicznych serwerów proxy jest rzeczywiście trudniejsze w Clojure niż w JavaScript. – TomSW

+0

Powiązane: http://stackoverflow.com/q/11144589/1348195 Wysłałem tam również odpowiedź przy użyciu nowego interfejsu API serwera proxy. –

Odpowiedz

61

Jest tylko jedna rzecz, istniejąca w tej chwili, że rzeczywiście może robić, co chcesz, ale niestety nie jest powszechnie stosowane:

Istnieją tylko dwa pracy implementacje dostępne w tej chwili, w najnowszych Firefox 4 beta (to jest już od FF3.7 wstępnych wersjach) oraz w node-proxy na stronie serwera JavaScript - Chrome i Safari aktualnie nad nim pracują-.

Jest jednym z early proposals dla next version of ECMAScript, to API, które pozwala na wdrożenie zwirtualizowanych obiekty (proxy), w którym można przypisać różne pułapek -callbacks-, które są wykonywane w różnych sytuacjach, zyskujesz pełną kontrolę nad tym, co w tym czasie - w ECMAScript 3/5- mogą robić tylko obiekty hosta.

Aby zbudować obiekt proxy, trzeba użyć metody Proxy.create, ponieważ jesteś zainteresowany set i get pułapek, zostawiam wam bardzo prosty przykład:

var p = Proxy.create({ 
    get: function(proxy, name) {  // intercepts property access 
    return 'Hello, '+ name; 
    }, 
    set: function(proxy, name, value) { // intercepts property assignments 
    alert(name +'='+ value); 
    return true; 
    } 
}); 

alert(p.world); // alerts 'Hello, world' 
p.foo = 'bar'; // alerts foo=bar 

Wypróbuj here.

Proxy API jest tak nowy, że nie jest nawet udokumentowane w Mozilla Developer Center, ale, jak powiedziałem, od czasu premier wersji Firefoksa 3.7 dołączono działającą implementację.

Przedmiotem Proxy jest dostępny w zasięgu globalnym i metoda create może trwać dwa argumenty, o handler obiekt, który jest po prostu obiekt, który zawiera właściwości nazwanych jako pułapki chcesz wprowadzić i opcjonalny proto argumentu, że umożliwia określenie obiektu, z którego dziedziczy serwer proxy.

Pułapki dostępne są:

// TrapName(args)       Triggered by 
// Fundamental traps 
getOwnPropertyDescriptor(name):   // Object.getOwnPropertyDescriptor(proxy, name) 
getPropertyDescriptor(name):    // Object.getPropertyDescriptor(proxy, name) [currently inexistent in ES5] 
defineProperty(name, propertyDescriptor): // Object.defineProperty(proxy,name,pd) 
getOwnPropertyNames():     // Object.getOwnPropertyNames(proxy) 
getPropertyNames():      // Object.getPropertyNames(proxy) 
delete(name):        // delete proxy.name 
enumerate():        // for (name in proxy) 
fix():         // Object.{freeze|seal|preventExtensions}(proxy) 

// Derived traps 
has(name):        // name in proxy 
hasOwn(name):        // ({}).hasOwnProperty.call(proxy, name) 
get(receiver, name):      // receiver.name 
set(receiver, name, val):     // receiver.name = val 
keys():         // Object.keys(proxy) 

Jedynym zasobem widziałem, oprócz wniosku przez siebie jest następujący poradnik:

Edit: Więcej informacji wychodzi, Brendan Eich niedawno wygłosił przemówienie na JSConf.eu konferencji można znaleźć tutaj swoje slajdy:

+1

Film Brendana Eicha wydaje się już niedostępny na stronie JSConf.eu. [Na szczęście jest teraz na YouTube] (http://youtu.be/sClk6aB_CPk). –

+0

Chrome ma również Proxy. – Pacerier

3

Nie wierzę w tego rodzaju metaprogramowanie możliwe jest (jeszcze) w javascript. Zamiast tego spróbuj użyć funkcji __noSuchMethod__, aby uzyskać efekt z właściwościami pobierającymi. Nie w przeglądarce, ponieważ jest to Mozilla extension.

var proxy = { 
    __noSuchMethod__: function(methodName, args) { 
     if(methodName.substr(0,3)=="get") { 
      var property = methodName.substr(3).toLowerCase();        
      if (property in this) { 
       return this[property]; 
      } 
     } 
    }, color: "red" 
}; 
alert(proxy.getColor());   
0

Jest __defineGetter__, __defineSetter__, __lookupGetter__ i __lookupSetter__ oprócz __noSuchMethod__ w SpiderMonkey.

4

Oto jak zdobyć zachowanie podobne do __noSuchMethod__

Przede wszystkim, oto prosty przedmiot z jednej metody:

var myObject = { 
    existingMethod: function (param) { 
     console.log('existing method was called', param); 
    } 
} 

teraz utworzyć proxy, który będzie złapać dostęp do właściwości/metody i dodaj swoje istniejący obiekt jako pierwszy parametr.

var myObjectProxy = new Proxy(myObject, { 
    get: function (func, name) { 
     // if property or method exists, return it 
     if(name in myObject) { 
      return myObject[name]; 
     } 
     // if it doesn't exists handle non-existing name however you choose 
     return function (args) { 
      console.log(name, args); 
     } 
    } 
}); 

Teraz spróbuj go:

myObjectProxy.existingMethod('was called here'); 
myObjectProxy.nonExistingMethod('with a parameter'); 

Pracuje w Chrome/Firefox/Opera. Nie działa w IE (ale działa już w Edge). Testowane również w mobilnej wersji Chrome.

Tworzenie proxy może być zautomatyzowane i niewidoczne, tzn. Jeśli używasz wzoru Factory do budowania obiektów. Zrobiłem to, aby stworzyć pracowników, których funkcje wewnętrzne można wywołać bezpośrednio z głównego wątku. Korzystanie z pracowników może być teraz tak proste dzięki tej nowej, świetnej funkcji o nazwie Proxy. Najprostsza implementacja dla robotów:

var testWorker = createWorker('pathTo/testWorker.js'); 
testWorker.aFunctionInsideWorker(params, function (result) { 
    console.log('results from worker: ', result); 
}); 
Powiązane problemy