【发布时间】:2011-03-20 17:39:47
【问题描述】:
背景
我一直在使用 C 预处理器来管理和“编译”具有多个文件和构建目标的半大型 javascript 项目。这使您可以从 javascript 中完全访问 C 预处理器指令,如 #include、#define、#ifdef 等。这是一个示例构建脚本,您可以测试示例代码:
#!/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
创建src和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 条件中,这样它就不会干扰应该遵循该宏的调用的花括号。
类OOP
让我们从一个 NAMESPACE 宏和一个不起眼但有用的 js 模式开始...
#define NAMESPACE(ns) var ns = this.ns = new function()
new function(){ ... } 做了一些简洁的事情。它将匿名函数作为构造函数调用,因此它不需要在末尾额外的() 来调用它,其中this 指的是构造函数正在创建的对象,即命名空间本身.这也允许我们在命名空间中嵌套命名空间。
这是我的全套类 OOP 宏:
#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);
}
}
}
EXTENDS 呢?
所以这给我带来了一个问题......我们如何将 EXTENDS 实现为宏来包装通常的“克隆原型,复制构造函数属性”js原型继承?除了要求 EXTENDS 出现在类定义之后 之外,我还没有找到一种方法,这很愚蠢。这个实验需要 EXTENDS 否则没用。随意更改其他宏,只要它们给出相同的结果。
编辑 - 这些对于 EXTENDS 可能会派上用场;为了完整起见,在此处列出它们。
#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(){}}())
提前感谢您提供的任何帮助、建议或热烈讨论。 :)
【问题讨论】:
标签: javascript shell macros preprocessor prototypal-inheritance