РАСШИРЯЕТ проблему: макросы функции препроцессора и подобное классу ООП

Фон

Я использовал препроцессор C, чтобы управлять и "скомпилировать" полубольшие проекты JavaScript с несколькими файлами и целями сборки. Это предоставляет полный доступ к директивам препроцессору C как #include, #define, #ifdef, и т.д. из JavaScript. Вот демонстрационный сценарий сборки, таким образом, можно протестировать пример кода:

#!/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

Сделайте a src и a build каталог, и вставленный в .js файлы src.


Макросы удобства

Первоначально, я просто хотел материал препроцессора для #include и возможно некоторые #ifdefs, но я добрался до взглядов, разве не будет хорошо иметь некоторые макросы удобства также? Экспериментирование последовало.

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

Прохладный, поэтому теперь я могу записать что-то вроде этого:

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

И это расширится до:

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

Как насчет 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) }

Заметьте, как мы крадемся v=o[k] в if условие, таким образом, это не нарушает фигурные скобки, которые должны следовать за вызовом этого макроса.


Подобное классу ООП

Давайте запустимся с макроса ПРОСТРАНСТВА ИМЕН и неясного, но полезного js шаблона...

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

new function(){ ... } делает некоторый аккуратный материал. Это вызывает анонимную функцию как конструктора, таким образом, этому не нужно дополнительное () в конце для вызова его, и в нем this относится к объекту, создаваемому конструктором, другими словами, само пространство имен. Это также позволяет нам пространствам имен вложенного множества в пространствах имен.

Вот мой полный набор подобных классу макросов ООП:

#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

Как Вы видите, они, макросы определяют много вещей оба в Variable Object (для удобства) и в this (от необходимости). Вот некоторый пример кода:

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

Что относительно РАСШИРЯЕТСЯ?

Таким образом, это приносит мне к вопросу..., как может мы реализовывать РАСШИРИТЬСЯ как макрос для обертывания обычного "клона прототип, свойства конструктора копии" js опытное наследование? Я не нашел способ сделать это за пределами требования, чтобы РАСШИРЕНИЕ появилось после определения класса, которое глупо. Для этого эксперимента нужно, РАСШИРЯЕТСЯ, или это бесполезно. Не стесняйтесь изменять другие макросы, пока они дают те же результаты.

Редактирование - Они могли бы пригодиться для, РАСШИРЯЕТСЯ; список их здесь для полноты.

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

Заранее спасибо за любую справку, совет или живое обсуждение.:)

7
задан Dagg Nabbit 28 July 2010 в 00:11
поделиться

1 ответ

Думаю, я только что выполнил свой собственный вызов. Я добавил второй (необязательный) аргумент в макрос объявления CLASS для суперкласса объявляемого класса.

Моя первоначальная реализация создавала много встроенного мусора вокруг конструктора, поэтому я решил обернуть некоторые вспомогательные функции во вспомогательный объект макроса, чтобы избежать избыточности.

Вот текущие воплощения моих классовых макросов ООП:

// class-like oo

#ifndef BASE
  #define BASE  $$_
#endif

#define COLLAPSE(code)      code

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

#define CLASS(c,__ARGS...)  var c=[BASE._class(this),[__ARGS][0]]; \
                            new function()

#define CTOR(c)             BASE._extend($$_##c,c[1],this); \
                            c=c[0].c=$$_##c; function $$_##c

#define PUBLIC(fn)          BASE._public(this).fn=fn;function fn

#define PRIVATE(fn)         function fn

#define STATIC(fn)          BASE._static(this).fn=fn;function fn

// macro helper object

COLLAPSE(var BASE=new function(){

  function Clone(){};

  function clone (obj) {
    Clone.prototype=obj; return new Clone;
  };

  function merge (sub, sup) { 
    for (var p in sup) if (sup.hasOwnProperty(p)) sub[p]=sup[p]; 
  };

  this._extend = function (sub, sup, decl) {
    if (sup) {
      merge(sub, sup);
      sub.prototype=clone(sup.prototype);
      sub.prototype.constructor=sub;
    };
    if (decl) {
      merge(sub.prototype, decl);
      decl._static=sub;
      decl._public=sub.prototype;
    };
  };

  this._static=this._ns=this._class=function (obj) {
    return (obj._static || obj); 
  };

  this._public=function (obj) {
    return (obj._public || obj); 
  };

})

... вот тестовое пространство имен ...

//#include "macros.js"

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

  // Customer extends Cashier, just so we can test inheritance

  CLASS (Customer, Cashier) {

    CTOR (Customer) (name) {
      this.name = name;
      this.inventory = [];
      this.transactions = 0;
    }

    PUBLIC (buy) (item, cashier) {
      cashier.sell(this, item);
    }

    CLASS (Cart) {

      CTOR (Cart) (customer) {
        this.customer = customer;
        this.items = [];
      }
    }

  }
}

... и вот результат ...

var $$_=new function(){ function Clone(){}; function clone (obj) { Clone.prototype=obj; return new Clone; }; function merge (sub, sup) { for (var p in sup) if (sup.hasOwnProperty(p)) sub[p]=sup[p]; }; this._extend = function (sub, sup, decl) { if (sup) { merge(sub, sup); sub.prototype=clone(sup.prototype); sub.prototype.constructor=sub; }; if (decl) { merge(sub.prototype, decl); decl._static=sub; decl._public=sub.prototype; }; }; this._static=this._ns=this._class=function (obj) { return (obj._static || obj); }; this._public=function (obj) { return (obj._public || obj); }; }
var Store=$$_._ns(this).Store=new function() {
  var Cashier=[$$_._class(this),[][0]]; new function() {
    var nextId = 1000;
    this.fullName = "floater";
    $$_._extend($$_Cashier,Cashier[1],this); Cashier=Cashier[0].Cashier=$$_Cashier; function $$_Cashier (fullName) {
      if (fullName) this.fullName = fullName;
      this.id = ++nextId;
      this.transactions = 0;
    }
    $$_._public(this).sell=sell;function sell (item, customer) {
      this.transactions += 1;
      customer.inventory.push(item);
    }
    $$_._static(this).hire=hire;function hire (count) {
      var newCashiers = [];
      for (var i=count; i--;) {
        newCashiers.push(new Cashier());
      }
      return newCashiers;
    }
  }
  var Customer=[$$_._class(this),[Cashier][0]]; new function() {
    $$_._extend($$_Customer,Customer[1],this); Customer=Customer[0].Customer=$$_Customer; function $$_Customer (name) {
      this.name = name;
      this.inventory = [];
      this.transactions = 0;
    }
    $$_._public(this).buy=buy;function buy (item, cashier) {
      cashier.sell(this, item);
    }
    var Cart=[$$_._class(this),[][0]]; new function() {
      $$_._extend($$_Cart,Cart[1],this); Cart=Cart[0].Cart=$$_Cart; function $$_Cart (customer) {
        this.customer = customer;
        this.items = [];
      }
    }
  }
}

Наследование, внутренние классы, и вложенные пространства имен работают нормально. Как вы думаете, полезен ли это подход к классическому ООП и повторному использованию кода в js? Сообщите мне, если я что-то пропустил.

2
ответ дан 7 December 2019 в 18:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: