2008-10-11 25 views
16

Sé que JavaScript no admite macros (estilo Lisp) pero me preguntaba si alguien tenía una solución para simular macros tal vez? Lo busqué en Google, y una de las soluciones sugirió usar eval(), pero como dijo, sería bastante costoso.¿Cómo puedo simular macros en JavaScript?

No tienen que ser muy elegantes. Solo quiero hacer cosas simples con ellos. Y no debería hacer que la depuración sea significativamente más difícil :)

Respuesta

-2

Se interpreta Javascript. Eval no es más costoso que cualquier otra cosa en Javascript.

+0

¡Mal! James, lea esta pregunta: http: //stackoverflow.com/questions/86513/why-is-using-javascript-eval-function-a-bad-idea#87260 y valide sus opiniones antes de hacer declaraciones engañosas. ¡La cadena que se pasa a un eval se debe analizar/interpretar cada vez que se llama a eval! – Ash

+0

Sí, la cadena pasada a eval debe analizarse cada vez que se invoca eval, pero también lo debe hacer cualquier otra línea de javascript. así es como funcionan los intérpretes. En cuanto a la respuesta a la que se vinculó, nunca menciona la velocidad, solo "mucho más fácil de leer y menos con errores potenciales" –

+2

Voy a conceder que posiblemente este haya sido el caso con Javascript en los navegadores que dicen alrededor de 2000, pero hoy en día se están aplicando optimizaciones serias al código Javascript simple (es decir, no evaluadas) y esto solo continuará. El código en una cadena en cualquier idioma tampoco se puede optimizar en ninguna parte. – Ash

22

Puede usar parenscript. Eso te dará macros para Javascript.

+0

-1 Si bien parenscript estaba bien en 2008, realmente debería usar ClojureScript ahora. –

+0

Diferentes soluciones ... Parenscript es una capa bastante delgada, a diferencia de ClojureScript. –

+2

No solo diferentes soluciones, también en diferentes idiomas –

5

He escrito un emulador de gameboy en javascript y simulo macros para la emulación de la CPU de esta manera:

código de macro (la función devuelve una cadena con el código de macro):

function CPU_CP_A(R,C) { // this function simulates the CP instruction, 
    return ''+    // sets CPU flags and stores in CCC the number 
    'FZ=(RA=='+R+');'+  // of cpu cycles needed 
    'FN=1;'+ 
    'FC=RA<'+R+';'+ 
    'FH=(RA&0x0F)<('+R+'&0x0F);'+ 
    'ICC='+C+';'; 
} 

Utilizando el "macro", por lo que se genera el código "sobre la marcha" y que no necesitamos para hacer llamadas de función a ella o escribir un montón de código repetidos para cada istruction ...

OP[0xB8]=new Function(CPU_CP_A('RB',4)); // CP B 
OP[0xB9]=new Function(CPU_CP_A('RC',4)); // CP C 
OP[0xBA]=new Function(CPU_CP_A('RD',4)); // CP D 
OP[0xBB]=new Function(CPU_CP_A('RE',4)); // CP E 
OP[0xBC]=new Function('T1=HL>>8;'+CPU_CP_A('T1',4)); // CP H 
OP[0xBD]=new Function('T1=HL&0xFF;'+CPU_CP_A('T1',4)); // CP L 
OP[0xBE]=new Function('T1=MEM[HL];'+CPU_CP_A('T1',8)); // CP (HL) 
OP[0xBF]=new Function(CPU_CP_A('RA',4)); // CP A 

Ahora w e puede ejecutar código emulado así:

OP[MEM[PC]](); // MEM is an array of bytes and PC the program counter 

creo que sirve ...

+2

¿El código fuente del emulador está disponible en cualquier lugar? –

+1

'new Function (string)' es un contexto 'eval()', y como tal, tiene las mismas características de rendimiento de 'eval()' – Havvy

+1

No creo que sea cierto. Puede ser una evaluación, pero la evaluación solo ocurre una vez. Una vez que es una función, debe ejecutarse cualquier cantidad de veces a la velocidad de funcionamiento normal. –

3
function unless(condition,body) { 
    return 'if(! '+condition.toSource()+'()) {' + body.toSource()+'(); }'; 
} 


eval(unless(function() { 
    return false; 
    }, function() { 
    alert("OK"); 
})); 
+0

No es una mala idea, pero, lamentablemente, la solución agrega demasiado una evaluación y definiciones de funciones 2x. +1 para intentar sin embargo. –

+1

Las macros se amplían en el momento de COMPILAR, por lo que debemos agregar la etapa de compilación a JavaScript u olvidarse de las macros. Podemos compilar JavaScript por llamada a la función eval() solamente, por lo que necesitamos eval() de todos modos. –

+0

macro son azúcares sintácticos para más consise y código expresivo. No aumentan teóricamente el tipo de cosas que puedes hacer o no. Se gastan una vez en el tiempo de compilación, lo que hace que el tiempo de ejecución cueste cero. El ejemplo aquí falla: eval se llamará cada vez y el código es más detallado y menos accesible que si se escribiera directamente el JavaScript equivalente. Para que las macros sean útiles, debería poder usarlas con una sintaxis como unless ('false', 'alert (' OK ')'); –

10

También se puede utilizar ahora para compilar ClojureScript clojure a javascript y obtener las macros de esa manera. Nota: ClojureScript usa Google Closure.

5

LispyScript es el último lenguaje que se compila en Javascript, que admite macros. Tiene una sintaxis de árbol como Lisp, pero también mantiene la misma semántica de Javascript. Descargo de responsabilidad: soy el autor de LispyScript.

+0

¿Es LispyScript un lenguaje homoicónico (como Scheme y Common Lisp)? –

+0

Sí LispyScript es homoicónico. Vea los documentos aquí. http://lispyscript.com – Santosh

+0

¿Está LispyScript relacionado con ParenScript de alguna manera? Se ven muy similares a mí, ya que ambos son dialectos Lisp que compilan a JavaScript. http://common-lisp.net/project/parenscript/ –

20

Una biblioteca de Mozilla (llamada SweetJS) está diseñada para simular macros en JavaScript. Por ejemplo, puede usar SweetJS para reemplazar la palabra clave function con def.

Cuestiones relacionadas