1 /* 2 * The contents of this file are subject to the Netscape Public 3 * License Version 1.1 (the "License"); you may not use this file 4 * except in compliance with the License. You may obtain a copy of 5 * the License at http://www.mozilla.org/NPL/ 6 * 7 * Software distributed under the License is distributed on an "AS 8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 9 * implied. See the License for the specific language governing 10 * rights and limitations under the License. 11 * 12 * The Original Code is mozilla.org code. 13 * 14 * The Initial Developer of the Original Code is Netscape 15 * Communications Corporation. Portions created by Netscape are 16 * Copyright (C) 1998 Netscape Communications Corporation. All 17 * Rights Reserved. 18 * 19 * Contributor(s): pschwartau (at) netscape.com, rogerl (at) netscape.com 20 * Date: 28 May 2001 21 * 22 * SUMMARY: Functions are scoped statically, not dynamically 23 * 24 * See ECMA Section 10.1.4 Scope Chain and Identifier Resolution 25 * (This section defines the scope chain of an execution context) 26 * 27 * See ECMA Section 12.10 The with Statement 28 * 29 * See ECMA Section 13 Function Definition 30 * (This section defines the scope chain of a function object as that 31 * of the running execution context when the function was declared) 32 */ 33 //------------------------------------------------------------------------------------------------- 34 var UBound = 0; 35 var bug = '(none)'; 36 var summary = 'Testing that functions are scoped statically, not dynamically'; 37 var self = this; // capture a reference to the global object 38 var status = ''; 39 var statusitems = [ ]; 40 var actual = ''; 41 var actualvalues = [ ]; 42 var expect= ''; 43 var expectedvalues = [ ]; 44 45 /* 46 * In this section the expected value is 1, not 2. 47 * 48 * Why? f captures its scope chain from when it's declared, and imposes that chain 49 * when it's executed. In other words, f's scope chain is from when it was compiled. 50 * Since f is a top-level function, this is the global object only. Hence 'a' resolves to 1. 51 */ 52 status = 'Section A of test'; 53 var a = 1; 54 function f() 55 { 56 return a; 57 } 58 var obj = {a:2}; 59 with (obj) 60 { 61 actual = f(); 62 } 63 expect = 1; 64 addThis(); 65 66 67 /* 68 * In this section the expected value is 2, not 1. That is because here 69 * f's associated scope chain now includes 'obj' before the global object. 70 */ 71 status = 'Section B of test'; 72 var a = 1; 73 var obj = {a:2}; 74 with (obj) 75 { 76 function f() 77 { 78 return a; 79 } 80 actual = f(); 81 } 82 // Mozilla result, which contradicts IE and the ECMA spec: expect = 2; 83 expect = 1; 84 addThis(); 85 86 87 /* 88 * Like Section B , except that we call f outside the with block. 89 * By the principles explained above, we still expect 2 - 90 */ 91 status = 'Section C of test'; 92 var a = 1; 93 var obj = {a:2}; 94 with (obj) 95 { 96 function f() 97 { 98 return a; 99 } 100 } 101 actual = f(); 102 // Mozilla result, which contradicts IE and the ECMA spec: expect = 2; 103 expect = 1; 104 addThis(); 105 106 107 /* 108 * Like Section C, but with one more level of indirection - 109 */ 110 status = 'Section D of test'; 111 var a = 1; 112 var obj = {a:2, obj:{a:3}}; 113 with (obj) 114 { 115 with (obj) 116 { 117 function f() 118 { 119 return a; 120 } 121 } 122 } 123 actual = f(); 124 // Mozilla result, which contradicts IE and the ECMA spec: expect = 3; 125 expect = 1; 126 addThis(); 127 128 129 /* 130 * Like Section C, but here we actually delete obj before calling f. 131 * We still expect 2 - 132 */ 133 status = 'Section E of test'; 134 var a = 1; 135 var obj = {a:2}; 136 with (obj) 137 { 138 function f() 139 { 140 return a; 141 } 142 } 143 delete obj; 144 actual = f(); 145 // Mozilla result, which contradicts IE and the ECMA spec: expect = 2; 146 expect = 1; 147 addThis(); 148 149 150 /* 151 * Like Section E. Here we redefine obj and call f under with (obj) - 152 * We still expect 2 - 153 */ 154 status = 'Section F of test'; 155 var a = 1; 156 var obj = {a:2}; 157 with (obj) 158 { 159 function f() 160 { 161 return a; 162 } 163 } 164 delete obj; 165 var obj = {a:3}; 166 with (obj) 167 { 168 actual = f(); 169 } 170 // Mozilla result, which contradicts IE and the ECMA spec: expect = 2; // NOT 3 !!! 171 expect = 1; 172 addThis(); 173 174 175 /* 176 * Explicitly verify that f exists at global level, even though 177 * it was defined under the with(obj) block - 178 */ 179 status = 'Section G of test'; 180 var a = 1; 181 var obj = {a:2}; 182 with (obj) 183 { 184 function f() 185 { 186 return a; 187 } 188 } 189 actual = String([obj.hasOwnProperty('f'), self.hasOwnProperty('f')]); 190 expect = String([false, true]); 191 addThis(); 192 193 194 /* 195 * Explicitly verify that f exists at global level, even though 196 * it was defined under the with(obj) block - 197 */ 198 status = 'Section H of test'; 199 var a = 1; 200 var obj = {a:2}; 201 with (obj) 202 { 203 function f() 204 { 205 return a; 206 } 207 } 208 actual = String(['f' in obj, 'f' in self]); 209 expect = String([false, true]); 210 addThis(); 211 212 213 214 //------------------------------------------------------------------------------------------------- 215 test(); 216 //------------------------------------------------------------------------------------------------- 217 218 219 function addThis() 220 { 221 statusitems[UBound] = status; 222 actualvalues[UBound] = actual; 223 expectedvalues[UBound] = expect; 224 UBound++; 225 resetTestVars(); 226 } 227 228 229 function resetTestVars() 230 { 231 delete a; 232 delete obj; 233 delete f; 234 } 235 236 237 function test() 238 { 239 enterFunc ('test'); 240 printBugNumber (bug); 241 printStatus (summary); 242 243 for (var i = 0; i < UBound; i++) 244 { 245 reportCompare(expectedvalues[i], actualvalues[i], statusitems[i]); 246 } 247 248 exitFunc ('test'); 249 } 250