4.9 压缩或解压缩JavaScript

JavaScript广泛用于网站设计。在编写JavaScript代码时,出于代码可读性与方便维护方面的考虑,我们有必要使用一些空格、注释和制表符。但是大量的空格以及制表符会增加JavaScript文件的大小。随着文件体积的增加,网页载入的时间也随之延长。因此,多数专业网站为了加快页面载入,都会对JavaScript文件进行压缩。通过压缩可以大幅度降低空白字符和换行符的数量。经过压缩的JavaScript,还可以通过加入足够的空白字符和换行符进行解压缩,这样就能够恢复代码的可读性。这则攻略就尝试在shell中发掘出类似的功能。

4.9.1 预备知识

我们准备写一个JavaScript压缩工具或代码混乱器,当然,还包括与之对应的解压缩工具。我们打算用文本与字符替换工具tr以及sed来试一试。下面来看看具体的做法。

4.9.2 工作原理

首先梳理一下对JavaScript进行压缩与解压缩的处理逻辑以及代码。

  1. $ cat sample.js
  2. functionsign_out()
  3. {
  4.  
  5. $("#loading").show();
  6. $.get("log_in",{logout:"True"},
  7.  
  8. function(){
  9.  
  10. window.location="";
  11.  
  12. });
  13.  
  14.  
  15. }

下面列出了为压缩JavaScript所需完成的工作。

  • 移除换行符和制表符。

  • 压缩空格。

  • 替换注释 /*内容*/

  • 替换下列内容:

    • "{ " 替换为 "{"

    • " }" 替换为 "}"

    • " (" 替换为 "("

    • ") " 替换为 ")"

    • ", " 替换为 ","

    • " ; " 替换为";" (我们需要移除所有多余的空格)

要解压缩或者恢复JavaScript的可读性,我们则需要执行下面的任务:

  • ";\n" 替换 ";"

  • "{\n" 替换 "{""\n}" 替换 "}"

4.9.3 工作原理

通过执行下面的步骤压缩JavaScript:

  • 移除 '\n''\t'
  1. tr -d '\n\t'
  • 移除多余的空格:
  1. tr -s ' '

或者

  1. sed 's/[ ]\+/ /g'
  • 移除注释:
  1. sed 's:/\*.*\*/::g'
  • 因为我们需要使用 /**/,所以以冒号作为sed的定界符,这样就不必对 / 进行转义了。

  • *sed 中被转义为 \*

  • .* 用来匹配 /**/ 之间所有的文本。

  • 移除{}();:以及逗号前后的所有空格。
  1. sed 's/ \?\([{ }();,:]\) \?/\1/g'

上面的sed语句含义如下所示。

  • sed代码中的 / \?([{ }();,:]) \?/ 用于匹配,/\1/g 用于替换。

  • ([{ }();,:]) 用于匹配集合 [ { }( ) ; , : ](出于可读性方面的考虑,在这里加入了空格)中的任意一个字符。()是分组操作符,用于记忆所匹配的内容,以便在替换部分中进行向后引用。对()转义之后,它们便具备了另一种特殊的含义,进而可以将它们作为分组操作符。位于分组操作符前后的 \? 用来匹配可能出现在字符集合前后的空格。

  • 在命令的替换部分,匹配字符串(也就是一个可选的空格、一个来自字符集的字符再加一个可选的空格)被匹配字符所替换。对于匹配字符,替换部分使用了向后引用,并通过组操作符()记录了匹配的字符内容。可以用符号 \1向后引用分组匹配的内容。

用管道将上面的步骤按照下列方式组合起来:

  1. $ catsample.js | \
  2. tr -d '\n\t' | tr -s ' ' \
  3. | sed 's:/\*.*\*/::g' \
  4. | sed 's/ \?\([{}();,:]\) \?/\1/g'

得到输出:

  1. functionsign_out(){$("#loading").show();$.get("log_in",{logout:"True"},function(){window.location="";});}

接下来,写一个可以将这些混乱的代码恢复正常的解压缩脚本:

  1. $ cat obfuscated.txt | sed 's/;/;\n/g; s/{/{\n\n/g; s/}/\n\n}/g'

或者

  1. $ cat obfuscated.txt | sed 's/;/;\n/g' | sed 's/{/{\n\n/g' | sed 's/}/\n\n}/g'

在上面的命令中:

  • s/;/;\n/g 将;替换为 \n;

  • s/{/{\n\n/g 将 { 替换为 {\n\n

  • s/}/\n\n}/g 将 } 替换为 \n\n}

4.9.4 参考

  • 2.6节讲解了tr命令。

  • 4.6节讲解了sed命令。