奇怪的Javascript "for"循环用法,请解释。

3

我发现了一段奇怪的JavaScript代码,但我无法理解。这个for循环有一个奇怪的语法(许多参数),能否说明它的工作原理?谢谢。

decode: function(s){
        for(var a, b, i = -1, l = (s = s.split("")).length, o = String.fromCharCode, c = "charCodeAt"; ++i < l;
            ((a = s[i][c](0)) & 0x80) &&
            (s[i] = (a & 0xfc) == 0xc0 && ((b = s[i + 1][c](0)) & 0xc0) == 0x80 ?
            o(((a & 0x03) << 6) + (b & 0x3f)) : o(128), s[++i] = "")
        );
        return s.join("");
    }
4个回答

5

这是一个普通的for循环,但第一部分有非常长的var语句。

就像这样:

var a, b, c;

在for循环中,迭代器语句包含了许多操作,而不是循环体实际上具有一个主体。

要么这个函数是由一个没有关注可读代码的糟糕程序员编写的,要么它被有意压缩和混淆了。


或者以某种方式这样做可以获得一些性能优势(真实的或想象的)。 - Erik Reppen
@Codemonkey:没有糟糕的程序员能写出那样的代码。 - SLaks
2
@SLaks 你错了。一个好的程序员不会在那里设置所有这些变量。一个好的程序员注重可读性。 - Florian Margaine

2

这是一个有趣的函数,显然是对一定字符集进行转码,有点深奥,只能使用ASCII码,但以下是详细说明:

    for (var i = 0; i < s.length; i++) {
        var a = s.charCodeAt(i);

        if (a & 0x80) { // (a >= 128) if extended ascii

            var b = s.charCodeAt(i + 1);

            var specialA = (a & 0xfc) === 0xc0; // a IS [À, Á, Â or Ã] essentially [192, 193, 194, 195]
            var specialB = (b & 0xc0) === 0x80; // b >= 128 & b <= 191 eg. b is not a special Latin Ascii Letter

            if (specialA && specialB) {

                var txA = (a & 0x03) << 6; // [0, 64, 128, 192]
                var txB = b & 0x3f; // 0 - 63

                s[i] = String.fromCharCode(txA + txB);

            } else {
                s[i] = String.fromCharCode(128);
                s[++i] = "";
            }
        }
    }

希望这能够帮到你,不管怎样我发现解码很有趣,就像阅读原始汇编一样,哈哈。-ck

有趣的解码技巧 n_n - ajax333221
谢谢,现在非常清楚!这应该是一个解码Unicode格式字符串的函数(例如,é应该被解码为é)。 - niente3

1

for循环的不同部分都在那里,由分号(;)分隔。

变量部分:

var a, b, i = -1, l = (s = s.split("")).length, o = String.fromCharCode, c = "charCodeAt";

检查部分:

++i < l;

更新部分:
((a = s[i][c](0)) & 0x80) &&
        (s[i] = (a & 0xfc) == 0xc0 && ((b = s[i + 1][c](0)) & 0xc0) == 0x80 ?
        o(((a & 0x03) << 6) + (b & 0x3f)) : o(128), s[++i] = "")

for()语句之后立即跟着一个;,这意味着循环没有主体,但是在变量、检查和更新部分的所有语句仍将被执行,直到检查不再为true
看起来有人并不想让他们的代码可读。你到底在哪里找到它的?

1

将循环拆分为更易读的形式:

  • 重新排列循环参数
  • 使用if(...){(...)}替换(...)&&(...)
  • l改为len
  • s = s.split(...)移至len之外

.

var a, b, s = s.split(""), o = String.fromCharCode, c = "charCodeAt";

for(var i = -1, len = s.length; ++i < len;){
    if((a = s[i][c](0)) & 0x80){
        (s[i] = (a & 0xfc) == 0xc0 && ((b = s[i + 1][c](0)) & 0xc0) == 0x80 ? o(((a & 0x03) << 6) + (b & 0x3f)) : o(128), s[++i] = "");
    }
}

  • 更改了 i 的初始值以及它的增加方式/位置
  • a = s[i][c](0) 移到外部

.

var a, b, s = s.split(""), o = String.fromCharCode, c = "charCodeAt";

for(var i = 0, len = s.length; i < len; i++){
    a = s[i][c](0);

    if(a & 0x80){
        s[i] = (a & 0xfc);
        (s[i] == 0xc0 && ((b = s[i + 1][c](0)) & 0xc0) == 0x80 ? o(((a & 0x03) << 6) + (b & 0x3f)) : o(128), s[++i] = "");
    }
}

  • 创建tmp使读取更容易
  • 将三元操作结果存储在tmp
  • 使用if(...){s[++i] = "";}来分割(s[i] == 0xc0 && tmp, s[++i] = "");
  • 替换了示例中的新循环

.

decode: function(s){
    var tmp, a, b, s = s.split(""), o = String.fromCharCode, c = "charCodeAt";

    for(var i = 0, len = s.length; i < len; i++){
        a = s[i][c](0);

        if(a & 0x80){
            s[i] = (a & 0xfc);

            if(((b = s[i + 1][c](0)) & 0xc0) == 0x80){
                tmp = o(((a & 0x03) << 6) + (b & 0x3f));
            }else{
                tmp = o(128);
            }

            if(s[i] == 0xc0 && tmp){
                s[++i] = "";
            }
        }
    }

    return s.join("");
}

最终结果 /\


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接