EXTENDE o desafio: macros de função de pré-processador e oop de classe

fundo

Eu tenho usado o pré-processador C para gerenciar e "compilar" projetos javascript semi-grandes com vários arquivos e criar destinos. Isso fornece acesso total às diretrizes do pré-processador C, como#include, #define, #ifdefetc. a partir do javascript. Aqui está um exemplo de script de construção para que você possa testar o código de exemplo:

#!/bin/bash
export OPTS="-DDEBUG_MODE=1 -Isrc"
for FILE in `find src/ | egrep '\.js?

Faça umsrc e umbuild diretório e coloque os arquivos .js emsrc.

Macros de conveniência

Originalmente, eu só queria o material do pré-processador para#include e talvez alguns#ifdefs, mas comecei a pensar: não seria legal ter algumas macros de conveniência também? Experimentação seguida.

#define EACH(o,k)     for (var k in o) if (o.hasOwnProperty(k))

Legal, então agora eu posso escrever algo como isto:

EACH (location, prop) {
  console.log(prop + " : " location[prop]);
}

E será expandido para:

for (var prop in location) if (location.hasOwnProperty(prop)) {
  console.log(prop + " : " location[prop]);
}

Que 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) }

Observe como nos esgueiramosv=o[k] dentro deif para que não perturbe os chavetas que devem seguir a invocação dessa macro.

OOP de classe

Vamos começar com uma macro NAMESPACE e um padrão js obscuro, mas útil ...

#define NAMESPACE(ns)    var ns = this.ns = new function()

new function(){ ... } faz algumas coisas legais. Ele chama uma função anônima como construtor, portanto, não precisa de um extra() no final para chamá-lo, e dentro delethis refere-se ao objeto que está sendo criado pelo construtor, em outras palavras, o próprio espaço para nome. Isso também nos permite aninhar namespaces dentro de namespaces.

Aqui está o meu conjunto completo de macros OOP de classe:

#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 você pode ver, essas macros definem muitas coisas, tanto noVariable Object (por conveniência) e emthis (por necessidade). Aqui está um exemplo de código:

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

E quanto a EXTENDS?

Então isso me leva à pergunta ... como podemos implementar EXTENDS como uma macro para agrupar o usual "clonar o protótipo, copiar propriedades do construtor" js herança do protótipo? Não encontrei uma maneira de fazer isso além de exigir que as EXTENDS apareçamdepois de a definição de classe, que é boba. Este experimento precisa de EXTENDS ou é inútil. Sinta-se livre para alterar as outras macros, desde que produzam os mesmos resultados.

Editar - pode ser útil para EXTENDS; listando-os aqui para verificar se estão completos.

#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(){}}())

Agradecemos antecipadamente por qualquer ajuda, conselho ou discussão animada. :)

` do echo "Processing $FILE" cat $FILE \ | sed 's/^\s*\/\/#/#/' \ | cpp $OPTS \ | sed 's/^[#:<].*// ; /^$/d' \ > build/`basename $FILE`; done

Faça umsrc e umbuild diretório e coloque os arquivos .js emsrc.

Macros de conveniência

Originalmente, eu só queria o material do pré-processador para#include e talvez alguns#ifdefs, mas comecei a pensar: não seria legal ter algumas macros de conveniência também? Experimentação seguida.

#define EACH(o,k)     for (var k in o) if (o.hasOwnProperty(k))

Legal, então agora eu posso escrever algo como isto:

EACH (location, prop) {
  console.log(prop + " : " location[prop]);
}

E será expandido para:

for (var prop in location) if (location.hasOwnProperty(prop)) {
  console.log(prop + " : " location[prop]);
}

Que 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) }

Observe como nos esgueiramosv=o[k] dentro deif para que não perturbe os chavetas que devem seguir a invocação dessa macro.

OOP de classe

Vamos começar com uma macro NAMESPACE e um padrão js obscuro, mas útil ...

#define NAMESPACE(ns)    var ns = this.ns = new function()

new function(){ ... } faz algumas coisas legais. Ele chama uma função anônima como construtor, portanto, não precisa de um extra() no final para chamá-lo, e dentro delethis refere-se ao objeto que está sendo criado pelo construtor, em outras palavras, o próprio espaço para nome. Isso também nos permite aninhar namespaces dentro de namespaces.

Aqui está o meu conjunto completo de macros OOP de classe:

#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 você pode ver, essas macros definem muitas coisas, tanto noVariable Object (por conveniência) e emthis (por necessidade). Aqui está um exemplo de código:

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

E quanto a EXTENDS?

Então isso me leva à pergunta ... como podemos implementar EXTENDS como uma macro para agrupar o usual "clonar o protótipo, copiar propriedades do construtor" js herança do protótipo? Não encontrei uma maneira de fazer isso além de exigir que as EXTENDS apareçamdepois de a definição de classe, que é boba. Este experimento precisa de EXTENDS ou é inútil. Sinta-se livre para alterar as outras macros, desde que produzam os mesmos resultados.

Editar - pode ser útil para EXTENDS; listando-os aqui para verificar se estão completos.

#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(){}}())

Agradecemos antecipadamente por qualquer ajuda, conselho ou discussão animada. :)

questionAnswers(1)

yourAnswerToTheQuestion