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 * 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