Home | History | Annotate | Download | only in Function
      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