AntecedentesAMPLÍA reto: macros de preprocesador de función y programación orientada a objetos de clase similar
He estado usando el preprocesador C para gestionar y "compilar" semi-grandes proyectos de javascript con varios archivos y construir objetivos. Esto le da acceso total a las directivas de preprocesador C como #include
, #define
, #ifdef
, etc. desde javascript. He aquí una muestra de escritura de la estructura para que pueda probar el código de ejemplo:
#!/bin/bash
export OPTS="-DDEBUG_MODE=1 -Isrc"
for FILE in `find src/ | egrep '\.js?$'`
do
echo "Processing $FILE"
cat $FILE \
| sed 's/^\s*\/\/#/#/' \
| cpp $OPTS \
| sed 's/^[#:<].*// ; /^$/d' \
> build/`basename $FILE`;
done
Hacer un directorio y una src
build
, y poner los archivos .js en src
.
Conveniencia macros
Originalmente, sólo quería las cosas preprocesador para #include
y tal vez un par de #ifdef
s, pero me puse a pensar, ¿no sería bueno tener algunos macros convenientes demasiado ? La experimentación se produjo.
#define EACH(o,k) for (var k in o) if (o.hasOwnProperty(k))
frío, así que ahora puedo escribir algo como esto:
EACH (location, prop) {
console.log(prop + " : " location[prop]);
}
Y se ampliará a:
for (var prop in location) if (location.hasOwnProperty(prop)) {
console.log(prop + " : " location[prop]);
}
¿Qué tal foreach?
#define FOREACH(o,k,v) var k,v; for(k in o) if (v=o[k], o.hasOwnProperty(k))
// ...
FOREACH (location, prop, val) { console.log(prop + " : " + val) }
Aviso cómo nos colamos v=o[k]
dentro de la condición if
por lo que no perturbe las llaves que deben seguir a la invocación de esta macro.
Clase-como programación orientada a objetos
Vamos a empezar con una macro espacio de nombres y un patrón de JS oscura pero útil ...
#define NAMESPACE(ns) var ns = this.ns = new function()
new function(){ ... }
hace algunas cosas muy buenas. Llama a una función anónima como un constructor, por lo que no necesita un ()
adicional al final para llamarlo, y dentro de él this
se refiere al objeto que está creando el constructor, en otras palabras, el propio espacio de nombres. Esto también nos permite anidar espacios de nombres dentro de espacios de nombres.
Aquí es mi juego completo de macros de programación orientada a objetos de clase similar:
#define NAMESPACE(ns) var ns=this.ns=new function()
#define CLASS(c) var c=this;new function()
#define CTOR(c) (c=c.c=this.constructor=$$ctor).prototype=this;\
function $$ctor
#define PUBLIC(fn) this.fn=fn;function fn
#define PRIVATE(fn) function fn
#define STATIC(fn) $$ctor.fn=fn;function fn
Como se puede ver, estas macros definen muchas cosas tanto en el Variable Object
(por conveniencia) y en this
(por necesidad). Aquí hay un código de ejemplo:
NAMESPACE (Store) {
CLASS (Cashier) {
var nextId = 1000;
this.fullName = "floater";
CTOR (Cashier) (fullName) {
if (fullName) this.fullName = fullName;
this.id = ++nextId;
this.transactions = 0;
}
PUBLIC (sell) (item, customer) {
this.transactions += 1;
customer.inventory.push(item);
}
STATIC (hire) (count) {
var newCashiers = [];
for (var i=count; i--;) {
newCashiers.push(new Cashier());
}
return newCashiers;
}
}
CLASS (Customer) {
CTOR (Customer) (name) {
this.name = name;
this.inventory = [];
this.transactions = 0;
}
PUBLIC (buy) (item, cashier) {
cashier.sell(this, item);
}
}
}
¿Y AMPLÍA?
Así que esto me lleva a la pregunta ... ¿cómo podemos implementar EXTENDS como una macro para envolver el habitual "clonar el prototipo, copiar las propiedades del constructor" js prototype inheritance? No he encontrado una manera de hacerlo fuera de requerir que el EXTENDS aparezca después de la definición de clase, que es tonto. Este experimento necesita EXTENSIÓN o es inútil. Siéntase libre de cambiar las otras macros siempre que den los mismos resultados.
Editar - Esto puede ser útil para EXTENDS; listando aquí para completar.
#define EACH(o,k) for(var k in o)if(o.hasOwnProperty(k))
#define MERGE(d,s) EACH(s,$$i)d[$$i]=s[$$i]
#define CLONE(o) (function(){$$C.prototype=o;return new $$C;function $$C(){}}())
Gracias de antemano por cualquier ayuda, consejo o discusión animada. :)
¿Cuáles son los beneficios comparados con GWT? – user123444555621
Bueno, esto sigue siendo javascript, simplemente se extendió con macros. El código GWT está escrito en java y 'compila' en javascript. Entonces, si está familiarizado con javascript y desea una forma conveniente de usar diseños familiares similares a clases, como espacios de nombres, declaraciones de clase con constructores dentro de ellos, herencia, etc., todos estos son posibles de emular en JavaScript, estas macros simplemente hacen es más conveniente. –