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 * Like scope-001.js, but using assignment var f = function expression 34 * instead of a function declaration: function f() {} etc. 35 */ 36 //------------------------------------------------------------------------------------------------- 37 var UBound = 0; 38 var bug = '(none)'; 39 var summary = 'Testing that functions are scoped statically, not dynamically'; 40 var self = this; // capture a reference to the global object 41 var status = ''; 42 var statusitems = [ ]; 43 var actual = ''; 44 var actualvalues = [ ]; 45 var expect= ''; 46 var expectedvalues = [ ]; 47 48 49 /* 50 * In this section the expected value is 1, not 2. 51 * 52 * Why? f captures its scope chain from when it's declared, and imposes that chain 53 * when it's executed. In other words, f's scope chain is from when it was compiled. 54 * Since f is a top-level function, this is the global object only. Hence 'a' resolves to 1. 55 */ 56 status = 'Section A of test'; 57 var a = 1; 58 var f = function () {return a;}; 59 var obj = {a:2}; 60 with (obj) 61 { 62 actual = f(); 63 } 64 expect = 1; 65 addThis(); 66 67 68 /* 69 * In this section the expected value is 2, not 1. That is because here 70 * f's associated scope chain now includes 'obj' before the global object. 71 */ 72 status = 'Section B of test'; 73 var a = 1; 74 var obj = {a:2}; 75 with (obj) 76 { 77 var f = function () {return a;}; 78 actual = f(); 79 } 80 expect = 2; 81 addThis(); 82 83 84 /* 85 * Like Section B , except that we call f outside the with block. 86 * By the principles explained above, we still expect 2 - 87 */ 88 status = 'Section C of test'; 89 var a = 1; 90 var obj = {a:2}; 91 with (obj) 92 { 93 var f = function () {return a;}; 94 } 95 actual = f(); 96 expect = 2; 97 addThis(); 98 99 100 /* 101 * Like Section C, but with one more level of indirection - 102 */ 103 status = 'Section D of test'; 104 var a = 1; 105 var obj = {a:2, obj:{a:3}}; 106 with (obj) 107 { 108 with (obj) 109 { 110 var f = function () {return a;}; 111 } 112 } 113 actual = f(); 114 expect = 3; 115 addThis(); 116 117 118 /* 119 * Like Section C, but here we actually delete obj before calling f. 120 * We still expect 2 - 121 */ 122 status = 'Section E of test'; 123 var a = 1; 124 var obj = {a:2}; 125 with (obj) 126 { 127 var f = function () {return a;}; 128 } 129 delete obj; 130 actual = f(); 131 expect = 2; 132 addThis(); 133 134 135 /* 136 * Like Section E. Here we redefine obj and call f under with (obj) - 137 * We still expect 2 - 138 */ 139 status = 'Section F of test'; 140 var a = 1; 141 var obj = {a:2}; 142 with (obj) 143 { 144 var f = function () {return a;}; 145 } 146 delete obj; 147 var obj = {a:3}; 148 with (obj) 149 { 150 actual = f(); 151 } 152 expect = 2; // NOT 3 !!! 153 addThis(); 154 155 156 /* 157 * Explicitly verify that f exists at global level, even though 158 * it was defined under the with(obj) block - 159 */ 160 status = 'Section G of test'; 161 var a = 1; 162 var obj = {a:2}; 163 with (obj) 164 { 165 var f = function () {return a;}; 166 } 167 actual = String([obj.hasOwnProperty('f'), self.hasOwnProperty('f')]); 168 expect = String([false, true]); 169 addThis(); 170 171 172 /* 173 * Explicitly verify that f exists at global level, even though 174 * it was defined under the with(obj) block - 175 */ 176 status = 'Section H of test'; 177 var a = 1; 178 var obj = {a:2}; 179 with (obj) 180 { 181 var f = function () {return a;}; 182 } 183 actual = String(['f' in obj, 'f' in self]); 184 expect = String([false, true]); 185 addThis(); 186 187 188 189 //------------------------------------------------------------------------------------------------- 190 test(); 191 //------------------------------------------------------------------------------------------------- 192 193 194 function addThis() 195 { 196 statusitems[UBound] = status; 197 actualvalues[UBound] = actual; 198 expectedvalues[UBound] = expect; 199 UBound++; 200 resetTestVars(); 201 } 202 203 204 function resetTestVars() 205 { 206 delete a; 207 delete obj; 208 delete f; 209 } 210 211 212 function test() 213 { 214 enterFunc ('test'); 215 printBugNumber (bug); 216 printStatus (summary); 217 218 for (var i = 0; i < UBound; i++) 219 { 220 reportCompare(expectedvalues[i], actualvalues[i], statusitems[i]); 221 } 222 223 exitFunc ('test'); 224 } 225