2017-03-16 5 views
0

Ich versuche, eine mehr Klassen-ähnliche Vererbung Modell mit JavaScript nachzuahmen, aber ich habe ein Problem, wenn Sie versuchen, dies mit der Idee von JavaScript Proxies zu mischen.Proxy-Nutzung vermasselt function.caller.name

Um eine lange Geschichte kurz, in der Definition meiner Klasse Typ mache ich eine Funktion _super haben() mit der Semantik „, wenn Methode X auf einer Instanz der Unterklasse B ruft _super(), rufen Sie die Methode X auf Eltern Klasse A ":

Class A 
    .X() {...} 
^
    | 
    | 
Class B 
    .X() {..._super(); ...} 

ich auf dem Funktion .caller.name Ansatz verlasse mir den Namen der rufenden Methode zu erhalten (in unserem Beispiel‚X‘). Dann rufe ich es in der Elternklasse an.

const Class = { 
... 
    _super: function _super(...args) { 
     // Get a handle on the function in which this function is invoked: 
     const callerMethod = _super.caller.name; 
     ... 
    }, 
... 
}; 

Dies funktioniert ordnungsgemäß. Die Probleme begannen, als ich ein Proxy-Objekt oberhalb meines Klassenkonstrukts hinzufügte (ich möchte einige Methodenaufrufe abfangen).

function traceMethodCalls(obj) { 
    const handler = { 
    get(target, propKey, receiver) { 
     const origMethod = target[propKey]; 
     return function (...args) { 
     // Do stuff 
     }; 
    }, 
    }; 
    return new Proxy(obj, handler); 
} 

Nun Funktion .caller im _super() -Methode ist die anonyme Funktion in dem Proxy-Handler-Objekt (natürlich ...), und dies vermasselt den Programmablauf auf.

Meine Frage: Gibt es eine Möglichkeit, dies zu umgehen? Oder anders darüber nachdenken? Oder muss ich den Ansatz * .caller.name insgesamt aufgeben?

Antwort

0

Die einzige Sache, die in den Sinn kommt, ist, den Stapel zu überprüfen, um das erste Ding zu finden, das nicht "_super" ist. Ziemlich albern IMO, aber hier geht es.

const Class = { 
 

 
    _super: function _super(...args) { 
 
     let callerMethod; 
 

 
     let s = (new Error) 
 
      .stack.split('\n') 
 
      .slice(2); 
 
     while (s.length && s[0].includes('_super')) 
 
      s.shift(); 
 

 
     let m = (s[0] || '').match(/^\s*at\s\w+\.(\w+)/); 
 
     callerMethod = m ? m[1] : null; 
 
     console.log('super call [%s]', callerMethod) 
 
    }, 
 

 
    foo: function() { 
 
     this._super() 
 
    } 
 
}; 
 

 

 
function traceMethodCalls(obj) { 
 
    const handler = { 
 
     get(target, propKey, receiver) { 
 
      const origMethod = target[propKey]; 
 
      let f = { 
 
       [propKey]: function (...args) { 
 
        console.log('tracing', propKey) 
 
        origMethod.bind(this)() 
 
       } 
 
      }; 
 
      return f[propKey]; 
 
     }, 
 
    }; 
 
    return new Proxy(obj, handler); 
 
} 
 

 
obj = Object.create(Class) 
 
obj.foo() 
 
traced = traceMethodCalls(obj) 
 
traced.foo()

Im Allgemeinen in immer gefährlich auf Funktionsnamen verlassen (man denke uglifiers et al). Ich denke, es wäre fair zu sagen, dass Sie nicht frei super arbeiten in js ohne irgendeine Art von Precompilation z. Anmerkungen.

+0

Danke! Ja, ich muss meinen Ansatz vielleicht überdenken. – Cristina