【问题标题】:Can bracket notation be used to compress/obfuscate JavaScript?可以使用括号表示法来压缩/混淆 JavaScript 吗?
【发布时间】:2015-04-18 00:46:00
【问题描述】:

这主要是出于学术原因,但我很好奇广泛使用括号表示法而不是点表示法是否有什么问题。

一些可能的应用可能包括:

  • 通过删除常用方法或属性的重复数据进一步压缩
  • 通过使去缩小的代码仍然难以理解/遵循来进一步混淆

我知道 gzip 压缩可能会使重复数据删除的好处变得无用,而 JavaScript 的混淆可能是徒劳的,因此我真的只是好奇这种技术在学术上的利弊。

考虑对这段代码进行以下一系列转换:

(function () {
    var parent, child;
    parent = document.body;

    child = document.createElement('div');
    child.setAttribute('foo', 'bar');
    parent.appendChild(child);
    parent = child;

    child = document.createElement('div');
    child.setAttribute('foo', 'bar');
    parent.appendChild(child);
    parent = child;

    child = document.createElement('div');
    child.setAttribute('foo', 'bar');
    parent.appendChild(child);
    parent = child;

    child = document.createElement('div');
    child.setAttribute('foo', 'bar');
    parent.appendChild(child);
    parent = child;

    child = document.createElement('div');
    child.setAttribute('foo', 'bar');
    parent.appendChild(child);
    parent = child;

    child = document.createElement('div');
    child.setAttribute('foo', 'bar');
    parent.appendChild(child);
    parent = child;

    child = document.createElement('div');
    child.setAttribute('foo', 'bar');
    parent.appendChild(child);
    parent = child;

    child = document.createElement('div');
    child.setAttribute('foo', 'bar');
    parent.appendChild(child);
    parent = child;
})();
  1. 为访问方法生成“常量”:

    var createElement = "createElement";
    var setAttribute = "setAttribute";
    var appendChild = "appendChild";
    
  2. 使用这些常量将点表示法调用替换为括号表示法调用

    child = document[createElement]('div');
    child[setAttribute]('foo', 'bar');
    parent[appendChild](child);
    
  3. 现在,mangler 可以将变量名和方法调用减少到单个字符

    var c = "createElement";
    var s = "setAttribute";
    var a = "appendChild";
    
    child = document[c]('div');
    child[s]('foo', 'bar');
    parent[a](child);
    

在缩小之后,这个人为的例子实现了 44% 的尺寸减小。

显然这不是手动完成的;它可能应该针对更常用的属性/方法针对 AST 进行。

全面使用括号表示法有什么好处吗?

我发现一些 SO 问题说它们是 pretty much the same,而一些涉及变量查找的声明括号表示法不能进行 JIT 优化并且速度要慢得多。还有microbenchmarks那种节目,所以我不太确定它到底在哪里。

我知道UglifyJS2 compressor options 默认优化属性访问,做相反的事情:将括号表示法转换为点表示法。我只是不知道它背后的原因,除非它真的只是为了节省 3 个额外的字符。

【问题讨论】:

    标签: javascript performance compression minify uglifyjs2


    【解决方案1】:

    它确实会导致某些引擎出现 JIT 问题。一个much simpler benchmark 没有将一打东西混为一谈,证明了这一点(下图)。所以你可以做到这一点,但你必须接受性能成本,这在某些引擎上很重要(例如,在 Chrome 上将属性访问速度降低了 ~64%;~86% 在 IE11 上,在我下面的简单测试中)。

    准备:

    var obj = {};
    var i;
    for (i = 0; i < 1000; ++i) {
        obj['prop' + i] = 'value ' + i;
    }
    var name = "prop257";
    

    测试obj.prop257

    if (obj.prop257 !== "value 257") throw "Error in test";
    

    测试obj[name]

    if (obj[name] !== "value 257") throw "Error in test";
    

    在 Chrome、Firefox、IE11 上运行的结果:

    在 Chrome (V8) 和 IE11 (JScript) 上,性能都大大降低。 Firefox (SpiderMonkey) 受到影响,但没有那么严重。

    【讨论】:

    • 非常有趣。我使用静态字符串而不是变量查找为括号表示法添加了第三个测试用例。在 Chrome 中,它似乎具有类似于点表示法的性能,这证明了 JIT 优化(并且在涉及变量查找时缺乏这种优化)。有趣的是,其他浏览器(我尝试过 Safari)可能不会执行此优化,因此这也可以解释 UglifyJS 的属性访问优化背后的原因。谢谢!
    • @DrSammyD:它有什么“更好”的地方?
    • @T.J. Crowder 您正在强制重新评估变量。他在谈论用于访问目的的根范围内的常量变量,您需要保持它们的恒定性,以免每次访问都引入 var 重新评估。
    • 一些疯狂优化的 Firefox 搞砸了我的浏览器比较结果。这个更好jsperf.com/bracket-v-dot-2
    • @DrSammyD:我的示例没有添加任何他没有添加的重新评估。你觉得有什么作用?
    猜你喜欢
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-23
    • 1970-01-01
    相关资源
    最近更新 更多