var buf = new UInt8Array(100); buf[0] = 123; // set alert(buf[0]); // get
然而 [] 操作符在 JS 里是无法重写的,因此难以将其变成 setter 和 getter。况且不支持 TypedArray 的都是低版本 IE,更不用考虑 ES6 的那些特征。
于是琢磨 IE 的私有接口。比如用 onpropertychange 事件来模拟 setter。不过这样做效率极低,而且 getter 仍不易实现。
经过一番考虑,决定不用钩子的方式,而是直接从源头上解决:修改语法!
我们用正则,找出源码中的赋值操作:
HEAP[index] = val;
替换成:
HEAP_SET(index, val);
类似的,将读取操作:
HEAP[index]
替换成:
HEAP_GET(index)
这样,原先的索引操作,就变成函数调用了。我们就能接管内存的读写,并且没有任何兼容性问题!
然后实现 8、16、32 位有无符号的读写。通过 JS 的 Array 来模拟,非常简单。
麻烦的是模拟 Float32 和 Float64 两个类型。不过本次 C 程序中并未用到浮点,所以就暂不实现了。
到此,兼容性问题就解决了。
大功告成解决了这些缺陷,我们就可以愉快的在 JS 中使用 C 逻辑了。
作为脚本,只关心采集哪些数据。这样 JS 代码就非常的优雅:
数据的储存、加密、编码,这些底层数据操作,则通过 C 实现。
编译时使用 -Os 优化体积。最终的 JS 混淆压缩之后,还不到 2 KB,十分小巧精炼。
更完美的是,我们只需维护一份代码,即可同时编译出前端和后端的版本。
于是,这个「前后端 WAF」开发就容易多了。
所有的编码/解码算法,都由 C 实现。然后分别编译成前端运行的 JS 代码,和后端 lua 模块,供 nginx-lua 使用。
测试版事实上,还有第三个版本 —— 本地版,用来测试算法逻辑。
这样就无需启动 WebServer、打开浏览器来调试了。只需模拟一些数据,运行程序即可测试,非常轻量。
同时借助 IDE,调试起来更容易。
小结每一门语言都有各自的优缺点。将不同语言的优势相互结合,可以程序变得更优雅、更完美。