JavaScript 无块级作用域

最近在做一系列JavaScript压缩工具,语法压缩,语义压缩,字符串压缩均有涉及(p.s.有趣的是, 压缩变量名之类的“有损压缩”不影响代码执行,但是字符串压缩这样的“无损压缩”却总是需要解压消耗)。

在实现压缩局部变量名时,最初的实现是将 if/else, for/in, do/while, switch/case/default, try/catch/finally, with和Object实例对象(后面统称为“块级作用域”)与function一样, 都作为独立的作用域,但是测试发现在JavaScript中并不是这么回事。

尝试着在块级作用域里声明定义变量:

if(true){
var bool=true;
}
document.write(bool); // output:true
1
2
3
4

会发现输出true,而且不论嵌套多深,也不论使用任何块级作用域进行嵌套,最后变量 依然如同在调用处之前,而且同级的作用域中定义的一样;值为在此之前,在块级作用域中所做改变的结果。 注意:如果块级作用域未被执行,则其中声明定义的变量会被声明(var name),但不被定义 (即未被初始化,此时name为undefined,引用name时不抛异常)。

if(false){var bool=true;}
document.write(bool); // output:undefined
1
2

之前虽知道,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
Help
[count]gg 跳转到第 [count] 行,默认第 1 行。
[count]G 跳转到第 [count] 行,默认最后一行。
[count]j 向下跳转 [count] 行,默认跳转一行。
[count]k 向上跳转 [count] 行,默认跳转一行。
/ 开始搜索。按 <Esc> 退出。
gh 跳转到首页。
gb 跳转到博客首页。
gw 跳转到 Wiki 首页。
gt 跳转到我的 Twitter Profile 页。
gp 跳转到我的 Github Profile 页。
? 打开帮助。按 <Esc> 退出。