2011-12-13 14 views
5

Sto sviluppando un'applicazione javascript che consiste di molti oggetti e funzioni (metodi oggetto). Voglio essere in grado di registrare molti eventi nel ciclo di vita dell'applicazione. Il mio problema è che all'interno del logger voglio sapere quale funzione ha richiamato la voce di log, così posso salvare quei dati insieme al messaggio di log. Ciò significa che ogni funzione deve in qualche modo essere in grado di fare riferimento a se stessa, quindi posso passare tale riferimento al registratore. Sto usando la modalità javascript strict, quindi l'utilizzo di arguments.callee all'interno della funzione non è consentito.Come fare riferimento a una funzione all'interno della propria implementazione?

Ecco un esempio di codice molto semplificato che è possibile eseguire. Sto solo usando qui alert invece del mio logger per semplicità.

(function(){ 
"use strict"; 

window.myObject = { 
    id : 'myObject', 
    myFunc : function(){ 
     alert(this.id); // myObject 
     alert(this.myFunc.id); // myFunc - I don't want to do this. I want something generic for all functions under any object 
     alert('???') // myFunc 
     alert(arguments.callee.id); // Will throw an error because arguments.callee in not allowed in strict mode 
    } 
} 
myObject.myFunc.id = 'myFunc'; 

myObject.myFunc(); 
})(); 
  1. Nel primo avviso - this relative al myObject e non myFunc
  2. Nel secondo avviso I - ho fatto riferimento alla funzione con il suo nome, che io non voglio fare, come ho Sto cercando un modo generico per fare riferimento a una funzione all'interno della sua stessa implementazione.
  3. Terzo avviso: apri le tue idee.
  4. Il quarto avviso - avrebbe funzionato se non avessi "use stict";. Voglio mantenere la modalità rigorosa poiché fornisce prestazioni migliori e costituisce una buona pratica di codifica.

Qualsiasi input sarà apprezzato.

Se non hai familiarità con la "rigorosa modalità", questo è un buon posto letto su di esso: JavaScript Strict Mode

risposta

4

Ecco un modo molto hacky di farlo:

(function(){ 
    "use strict"; 
    window.myObject = { 
     id: 'myObject', 
     myFunc: function() { 
      // need this if to circumvent 'use strict' since funcId doesn't exist yet 
      if (typeof funcId != 'undefined') 
       alert(funcId); 
     }, 
     myFunc2: function() { 
      // need this if to circumvent 'use strict' since funcId doesn't exist yet 
      if (typeof funcId != 'undefined') 
       alert(funcId); 
     } 
    } 
    // We're going to programatically find the name of each function and 'inject' that name 
    // as the variable 'funcId' into each function by re-writing that function in a wrapper 
    for (var i in window.myObject) { 
     var func = window.myObject[i]; 
     if (typeof func === 'function') { 
      window.myObject[i] = Function('var funcId = "' + i + '"; return (' + window.myObject[i] + ')()'); 
     } 
    } 

    window.myObject.myFunc(); 
    window.myObject.myFunc2(); 
})(); 

In sostanza, stiamo aggirando la dichiarazione 'use strict' ricompilando ogni funzione da una stringa dopo abbiamo scoperto che il nome della funzione. Per fare questo, creiamo un wrapper attorno a ciascuna funzione che dichiara una variabile stringa 'funcId' uguale al nome della nostra funzione di destinazione, in modo che la variabile sia ora esposta alla funzione all'interno di attraverso la chiusura.

Eh, non è il modo migliore di fare le cose, ma funziona. alternativa, si può semplicemente chiamare una funzione non rigorosa dall'interno:

(function(){ 
    "use strict"; 

    window.myObject = { 
     id: 'myObject', 
     myFunc: function() { 
      alert(getFuncName()) 
     }, 
     myFunc2: function() { 
      alert(getFuncName()); 
     } 
    } 
})(); 

// non-strict function here 
function getFuncName(){ 
    return arguments.callee.caller.id; // Just fyi, IE doesn't have id var I think...so you gotta parse toString or something 
} 

Speranza che aiuta.

+0

Grazie! Queste sono soluzioni interessanti :) –

0
myFunc : function _myFunc(){ 
    alert(_myFunc); // function 
} 

Nome le funzioni e fare riferimento direttamente

Per risolvere il vostro scopo di registrazione , usa messaggi di registrazione unici e sensati. Se si desidera ottenere informazioni sulla linea, generare un'eccezione.

+1

Sto cercando qualcosa di più generico quindi non devo sempre fare riferimento a ciascuna funzione con il suo nome. Come 'this' si riferisce al contesto e non devo usare il nome del contesto. –

+0

@OrrSiloni non esistono. Usa il nome delle funzioni. inoltre, tutte le tue funzioni dovrebbero avere un nome, ricorda. – Raynos

+0

Sto iniziando a pensare che non ci possa essere alcuna via di fuga dal passare il nome della funzione al registratore. Spero ancora che qualcuno mi sorprenda con una soluzione elegante. –

0

Non penso che quello che vuoi fare (trovare il nome della funzione corrente) sia molto facile da fare. Si potrebbe voler esaminare l'aggiunta di una fase di pre-elaborazione (come avviene per le cose come __line__ in C), ma forse solo un po 'OO/currying magia fa il trucco:

function logger(id){ return function(msg){ 
    return console.log(id, msg); 
};} 

window.myObject = { 
    id : 'myObject', 
    myFunc : function(){ 
     var log = logger('myFunc'); 

     log(1); //prints "Myfunc, 1" 
     log(2); //prints "Myfunc, 2" 
    } 
}; 

Questa è una specie di un poliziotto fuori, ma è molto semplice e può essere ragionevolmente maneggevole se ti ricordi solo di tenere gli id ​​e i nomi delle funzioni in pista.

+0

È un buon approccio, ma dovrò sempre richiamare il logger all'inizio di ogni funzione e passargli il nome della funzione come stringa, che è quello che stavo cercando di evitare per cominciare. –

+0

@OrrSiloni: lo so, ma almeno lo devi fare solo una volta e funziona anche con funzioni anonime senza nome e nomi multipli nella stessa funzione. – hugomg

Problemi correlati