背景
我一直在使用 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
,也许是几个#ifdef
s,但我开始想,有一些方便的宏不是很好吗?实验随之而来。
#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实现为宏来包装通常的“克隆原型,复制构造函数属性”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(){}}())
提前感谢您的任何帮助、建议或热烈讨论。:)