将 duff 的设备从 C 移植到 JavaScript

Porting duff's device from C to JavaScript

我在 C 中有这种 Duff 的设备,它工作正常(将文本格式设置为货币):

#include <stdio.h>
#include <string.h>

char *money(const char *src, char *dst)
{
    const char *p = src;
    char *q = dst;
    size_t len;

    len = strlen(src);
    switch (len % 3) {
        do {
            *q++ = ',';
            case 0: *q++ = *p++;
            case 2: *q++ = *p++;
            case 1: *q++ = *p++;
        } while (*p);
    }
    *q++ = 0;
    return dst;
}

int main(void)
{
    char str[] = "1234567890123";
    char res[32];

    printf("%s\n", money(str, res));
    return 0;
}

输出:

1,234,567,890,123

但是我在 Javascript 中尝试实现相同的方法时遇到了问题:

function money(src, dst) {
    var len = src.length;
    var i = 0;

    switch (len % 3) {
        do {
            dst += ',';
            case 0: dst += src[i++];
            case 2: dst += src[i++];
            case 1: dst += src[i++];
        } while (src[i]);
    }
    return dst;
}

var str = "1234567890123";
var res = "";

console.log(money(str, res));

nodejs returns 这个错误:

        do {
        ^^
SyntaxError: Unexpected token do

我的问题是:javascript 是否支持计算 GOTO 语句?

P.D:我不想要替代方案,我只想知道为什么不起作用。

相关问题:Does Duff's Device work in other languages?

JavaScript switch 语句不是那样工作的。

switch (expr) {
  case expr:
    statements;
    break;
  case expr:
    statements;
    break;
  default:
    statements;
    break;
}

但是 JavaScript 确实提供 labels 来控制您的循环

Example from MDN

var itemsPassed = 0;
var i, j;

top:
for (i = 0; i < items.length; i++){
  for (j = 0; j < tests.length; j++) {
    if (!tests[j].pass(items[i])) {
      continue top;
    }
  }

  itemsPassed++;
}

Another example from MDN

var allPass = true;
var i, j;

top:
for (i = 0; items.length; i++)
  for (j = 0; j < tests.length; i++)
    if (!tests[j].pass(items[i])){
      allPass = false;
      break top;
    }

My question is: Does javascript supports computed GOTO statements?

不是真的

P.D: I don't want an alternative, I just want to know why is not working.

它不起作用,因为在 JavaScript、switch statements must only contain case blocks

虽然 可能不在寻找解决方法,但 其他人 可能会找到这个问题来寻找解决方法,所以我'无论如何都会提供一个。
此功劳归功于 mnieper who suggested it at asm.js.

基本思路是在顶层有一个 while(true) 循环,里面有一个 switch 语句。

goto:
while(true)
{
    switch(where)
    {
        // no breaks
        case 0:
            // some code...
        case 1:
            // some other code...
        // ...
    }
}

为了模拟 goto,可以使用

where = 1;
continue goto;

为了模拟 duff 的设备,只需将循环作为外部结构,并在 switch 语句中使用一个变量,该变量在第一次迭代后设置为将触发 switch 语句的值从第一个案例开始。

所以在你的情况下,这意味着交换 switchdo...while() 并添加一个 default 案例和一个控制变量:

var where = len % 3;
do {
    switch (where) {
        default: dst += ',';
        case 0:  dst += src[i++];
        case 2:  dst += src[i++];
        case 1:  dst += src[i++];
    }
    where = -1;
} while (src[i]);

一般来说,这种方法的一个巨大缺点当然是它不能跨回调工作,回调在 JavaScript.
中几乎无处不在。 不过,只要它在单个顺序上下文中使用,它就应该可以工作。

有关详细信息,请参阅 the ticket posted on the asm.js repo