2011-12-13 18 views
5

Estoy desarrollando una aplicación de JavaScript que consta de muchos objetos y funciones (métodos de objetos). Quiero poder registrar muchos eventos en el ciclo de vida de la aplicación. Mi problema es que dentro del registrador quiero saber qué función invocó la entrada del registro, así que puedo guardar esos datos junto con el mensaje de registro. Esto significa que cada función debe ser de alguna manera capaz de referenciarse a sí misma, por lo que puedo pasar esa referencia al registrador. Estoy usando el modo estricto de JavaScript, por lo que no está permitido usar arguments.callee dentro de la función.¿Cómo hacer referencia a una función desde su propia implementación?

Aquí hay una muestra de código muy simplificado que puede ejecutar. Solo estoy usando aquí alert en lugar de mi registrador para simplificar.

(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. En la primera alerta - this relacionada con myObject y no a myFunc
  2. En la segunda alerta I - I hace referencia a la función por su nombre, que no quiero hacer, como yo Estoy buscando una forma genérica para hacer referencia a una función desde su propia implementación.
  3. La tercera alerta: abierta para sus ideas.
  4. La cuarta alerta: habría funcionado si no hubiera "use stict";. Quiero mantener el modo estricto ya que proporciona un mejor rendimiento y constituye una buena práctica de codificación.

Cualquier entrada será apreciada.

Si usted no está familiarizado con el "modo estricto", este es un buen lugar leer sobre él: JavaScript Strict Mode

Respuesta

4

Aquí está una manera poco limpia de hacerlo:

(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(); 
})(); 

Esencialmente, estamos eludiendo la declaración 'use strict' recompilando cada función de una cadena después de que hemos encontrado el nombre de esa función. Para hacer esto, creamos un contenedor alrededor de cada función que declara que una variable de cadena 'funcId' es igual al nombre de nuestra función objetivo, de modo que la variable está ahora expuesta a la función dentro del cierre.

Eh, no es la mejor manera de hacer las cosas, pero funciona. Alternativamente, sólo tiene que llamar a una función no estricto desde dentro:

(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 
} 

Espero que ayude.

+0

¡Gracias! Esas son soluciones geniales :) –

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

Nombre sus funciones y hacer referencia a ellos directamente

Para resolver su propósito de registro , use mensajes de registro únicos y reales. Si desea información de línea, genere una excepción.

+1

Estoy buscando algo más genérico, así que no siempre tengo que hacer referencia a cada función por su nombre. Como 'this' se refiere al contexto y no tengo que usar el nombre del contexto. –

+0

@OrrSiloni no existen. Usa el nombre de las funciones. además, todas tus funciones deben tener un nombre, recuerda. – Raynos

+0

Estoy empezando a pensar que puede haber escapatoria para pasar el nombre de la función al registrador. Todavía espero que alguien me sorprenda con una solución elegante. –

0

No creo que lo que quiere hacer (encontrar el nombre de la función actual) es muy fácil de hacer. Es posible que desee ver en la adición de un paso de preprocesamiento (como se hace para cosas como __line__ en C), pero tal vez sólo un poco OO/currying magia hace el truco:

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" 
    } 
}; 

Esta es una especie de un policía, pero es muy simple y puede ser razonablemente conservable si simplemente recuerda mantener los ids y nombres de funciones en la pista.

+0

Es un enfoque agradable, pero tendré que invocar siempre el registrador al inicio de cada función y pasarle el nombre de la función como cadena, que es lo que estaba tratando de evitar para empezar. –

+0

@OrrSiloni: Lo sé, pero al menos solo tienes que hacerlo una vez y también funciona con funciones anónimas sin nombre y múltiples nombres en la misma función. – hugomg

Cuestiones relacionadas