最近在做一系列JavaScript压缩工具,语法压缩,语义压缩,字符串压缩均有涉及(p.s.有趣的是, 压缩变量名之类的“有损压缩”不影响代码执行,但是字符串压缩这样的“无损压缩”却总是需要解压消耗)。
在实现压缩局部变量名时,最初的实现是将 if/else, for/in, do/while, switch/case/default, try/catch/finally, with和Object实例对象(后面统称为“块级作用域”)与function一样, 都作为独立的作用域,但是测试发现在JavaScript中并不是这么回事。
尝试着在块级作用域里声明定义变量:
会发现输出true,而且不论嵌套多深,也不论使用任何块级作用域进行嵌套,最后变量 依然如同在调用处之前,而且同级的作用域中定义的一样;值为在此之前,在块级作用域中所做改变的结果。 注意:如果块级作用域未被执行,则其中声明定义的变量会被声明(var name),但不被定义 (即未被初始化,此时name为undefined,引用name时不抛异常)。
之前虽知道,IE里for(var i=0;...)里定义的i,在for之外也是可以使用的,但是现在才知道这种情况更为猖獗, 大出我的意料之外,而更意外的是,IE 7(IE6?), Firefox 3(FF1,FF2?), Opera 9, Chrome 1, Safari 3表现均丝毫不差。
虽然与某些编程规范不同,但是js就是这样了,唉。早知道这样,压缩变量名这部分也就不用那么费劲了,只得重写了。
另外还有一些JavaScript作用域方面的文章:
[http://www.blueidea.com/tech/web/2007/4855.asp JavaScript中的作用域],好像是realazy翻译的,
文章很好,虽然有点文不对题(主要阐述this的作用域链问题)。
[http://www.cnblogs.com/3zfp/archive/2008/10/24/528644.html js变量作用域及可访问性的探讨],
详细介绍了各种变量的作用域及其可访问性问题。
附A 测试代码:
// Global Scope
if (true){
var v10 = true;
}else {
var v00 = false;
}
document.write("v10 : "+v10+"<br />");
document.write("v00 : "+v00+"<br />");
document.write("<hr />");
// Function Scope
function functionScopes(){
if (true){
// 以下均执行
var v11 = true;
do{
var v12 = true;
}while (false);
while (true){
var v13 = true;
break;
}
switch (1){
case 1:
var v14 = true;
default:
var v15 = true;
}
try{
var v16 = true;
throw new Error("");
}catch(e){
var v17 = true;
}finally{
var v18 = true;
}
for (var v19=0; v19<1; v19++){
var v1a=true;
}
with(v11){
var v1b = true;
}
function inn1(){
var inn11 = false;
}
}else {
// 以下均未执行
var v01 = false;
do{
var v02 = false;
}while (false);
while (false){
var v03 = false;
}
try{
var v06 = true;
throw new Error("");
}catch(e){
var v07 = true;
}finally{
var v08 = true;
}
switch (1){
case 1:
var v04 = true;
default:
var v05 = false;
}
for (var v09=0; v09<1; v09++){
var v0a=true;
}
with(v01){
var v0b = true;
}
function inn0(){
var inn01 = false;
}
}
document.write("v11 : "+v11+"<br />");
document.write("v12 : "+v12+"<br />");
document.write("v13 : "+v13+"<br />");
document.write("v14 : "+v14+"<br />");
document.write("v15 : "+v15+"<br />");
document.write("v16 : "+v16+"<br />");
document.write("v17 : "+v17+"<br />");
document.write("v18 : "+v18+"<br />");
document.write("v19 : "+v19+"<br />");
document.write("v1a : "+v1a+"<br />");
document.write("v1b : "+v1b+"<br />");
document.write("<hr />");
document.write("v01 : "+v01+"<br />");
document.write("v02 : "+v02+"<br />");
document.write("v03 : "+v03+"<br />");
document.write("v04 : "+v04+"<br />");
document.write("v05 : "+v05+"<br />");
document.write("v06 : "+v06+"<br />");
document.write("v07 : "+v07+"<br />");
document.write("v08 : "+v08+"<br />");
document.write("v09 : "+v09+"<br />");
document.write("v0a : "+v0a+"<br />");
document.write("v0b : "+v0b+"<br />");
document.write("<hr />");
try{alert(inn11);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(inn01);}catch(e){document.write((e.message||e)+"<br />");}
}
functionScopes();
document.write("<hr />");
try{alert(v11);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v12);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v13);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v14);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v15);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v16);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v17);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v18);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v19);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v1a);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v1b);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v01);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v02);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v03);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v04);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v05);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v06);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v07);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v08);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v09);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v0a);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v0b);}catch(e){document.write((e.message||e)+"<br />");}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
附B 测试结果(IE 7, FF 3, Opera 9, Safari 3, Chorme 1均同):
v10 : true v00 : undefined v11 : true v12 : true v13 : true v14 : true v15 : true v16 : true v17 : true v18 : true v19 : 1 v1a : true v1b : true v01 : undefined v02 : undefined v03 : undefined v04 : undefined v05 : undefined v06 : undefined v07 : undefined v08 : undefined v09 : undefined v0a : undefined v0b : undefined 'inn11' 未定义 'inn01' 未定义 'v11' 未定义 'v12' 未定义 'v13' 未定义 'v14' 未定义 'v15' 未定义 'v16' 未定义 'v17' 未定义 'v18' 未定义 'v19' 未定义 'v1a' 未定义 'v1b' 未定义 'v01' 未定义 'v02' 未定义 'v03' 未定义 'v04' 未定义 'v05' 未定义 'v06' 未定义 'v07' 未定义 'v08' 未定义 'v09' 未定义 'v0a' 未定义 'v0b' 未定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48