3

我正在观看 2011 年的 Google I/O 演示文稿https://www.youtube.com/watch?v=M3uWx-fhjUc

在 39:31 分钟,Michael 展示了闭包编译器的输出,如下所示。

我的问题是这段代码到底在做什么(如何以及为什么)

// Question #1 - floor & random? 2147483648?
Math.floor(Math.random() * 2147483648).toString(36);

var b = /&/g, 
    c = /</g,d=/>/g, 
    e = /\"/g, 
    f = /[&<>\"]/;

// Question #2 - sanitizing input, I get it... 
// but f.test(a) && ([replaces]) ?
function g(a) {
   a = String(a);

   f.test(a) && (
      a.indexOf("&") != -1 && (a = a.replace(b, "&amp;")), 
      a.indexOf("<") != -1 && (a = a.replace(c, "&lt;")), 
      a.indexOf(">") != -1 && (a = a.replace(d, "&gt;")),
      a.indexOf('"') != -1 && (a = a.replace(e, "&quot;"))
   );

   return a;
};

// Question #3 - void 0 ???    
var h = document.getElementById("submit-button"),
    i,
    j = {
       label: void 0,
       a: void 0
    };
i = '<button title="' + g(j.a) + '"><span>' + g(j.label) + "</span></button>";
h.innerHTML = i;

编辑

感谢您富有洞察力的答案。我仍然对编译器在脚本顶部生成随机字符串的原因感到非常好奇。当然,这一定是有充分理由的。任何人???

4

4 回答 4

2

如有疑问,请检查其他基地。

2147483648(基数 10)= 0x80000000(基数 16)。所以它只是制作一个在 32 位有符号范围内的随机数intfloor将其转换为实际的 int,然后toString(36)将其转换为 36 个字符的字母表,即 0-9(10 个字符)加上 az(26 个字符)。

第一行的最终结果是一串随机数字和字母。其中将有 6 个(36^6 = 2176782336),但第一个不会像其他的那样随机(在字母表中不会迟到)。编辑:阿德里安在他的回答中已经正确地解决了这个问题;第一个字母可以是 36 个字符中的任何一个,但不太可能是 Z。其他字母对较低值的偏差很小。

对于问题 2,如果您的意思是这样a = String(a);,那么是的,它确保这a是一个字符串。这也是对编译器的一个提示,以便它可以在能够将其转换为机器代码时进行更好的优化(不过我不知道它们是否可以用于字符串)。

编辑:好的,你澄清了这个问题。f.test(a) && (...)是使用短路评估的常见技巧。它实际上是在说if(f.test(a)){...}。不要在实际代码中那样使用它,因为它会降低可读性(尽管在某些情况下它更具可读性)。如果您想知道test,它与正则表达式有关。

对于问题3,这对我来说也是新的!但请看这里:“void 0”是什么意思?(快速谷歌搜索。结果很有趣,但很奇怪)

于 2013-08-21T22:29:20.573 回答
2

有许多不同的问题合二为一,但考虑到问题标题,我将只关注第一个问题:

Math.floor(Math.random() * 2147483648).toString(36);

实际上,这并没有做任何事情- 因为值被丢弃而不是分配。但是,这样做的想法是生成一个介于 0 和 2 ^ 31 - 1 之间的数字,并以 36 为基数返回。

Math.random() 返回一个从 0(包括)到 1(不包括)的数字。然后将其乘以 2^31 以产生提到的范围。然后.toString(36)将其转换为基数 36,由 0 到 9 后跟 A 到 Z 表示。

最终结果的范围从 0 到(我相信)ZIK0ZI。

至于为什么它首先在那里......好吧,检查幻灯片。这条线出现在顶部。虽然这纯粹是猜想,但我实际上怀疑代码被裁剪为可见的,并且在其上方有一些东西被分配给了它。

于 2013-08-21T22:29:34.917 回答
2

1)我不知道数字 1 的意义是什么。

2) 看起来要确保任何符号都正确地转换成它们对应的HTML 实体,所以基本上是清理输入以确保它是 HTML 安全的

3)void 0本质上是确保它返回的一种非常安全的方法undefined。由于undefinedjavascript 中的实际关键字是可变的(即可以设置为其他值),因此假设undefined实际上等于您期望的未定义值并不总是安全的。

于 2013-08-21T22:31:25.880 回答
2

1)此代码是从闭包库中提取的。此代码只是创建随机字符串。在以后的版本中,它已被替换为简单地创建一个大的随机整数,然后将其连接到一个字符串:

'closure_uid_'  + ((Math.random() * 1e9) >>> 0)

这个简化的版本更容易被 Closure Compiler 删除,所以你不会像以前那样看到它的剩余部分。具体来说,编译器假定没有参数的“toString”不会导致可见的状态变化。但是,它不会对带参数的 toString 调用做出相同的假设。您可以在此处阅读有关编译器假设的更多信息:

https://code.google.com/p/closure-compiler/wiki/CompilerAssumptions

2) 在某些时候,假设大多数字符串不需要转义,有人确定在进行“替换”调用之前测试可能需要替换的字符会更快。

3) 正如其他人所说,void 运算符总是返回 undefined,而“void 0”只是写“undefined”的一种合理方式。在正常使用中它是非常无用的。

于 2013-08-22T21:59:14.963 回答