Javascript closures - behavior of overridden funct

2019-07-16 12:32发布

问题:

This question is more on javascript principle.

function done(){ console.log('done defined with `function done(){ ...`'); }
var done = function(){ console.log('done defined with `var done = ...`'); }
done = function(){ console.log('without `var`, just `done = ...`'); }

If defined right inside <script> tags, will they all do the same thing, right?

But if I place them in a closure (function(){ function definintion goes here }()) will any of these three types override either the globally defined function done() or any other done() functions that are defined inside their respective closures?

If the question above doesn't make sense, here's to rephrasing;

  • is the following code supposed to do the same thing in any JS runtime?
  • eval-ing code anywhere executes that particular code within the context or the global scope?
  • how can a setTimeout call be configured so that the code between its "quotes" executes to inside the scope where that particular setTimeout has been called (please see second timeout inside for below)? I mean is there any other way besides defining window.blabla functions and telling them to delete themselves after they run?

    function done(d){ console.log('cha cha cha: '+d); }
    setTimeout( function(){ done(2); }, 3500 );
    
    for(i=0; i<10; i++){
        (function(){
            done = function(x){ console.log('done #'+i+' sais: '+x); }
            setTimeout(function(){ done(i*2); },2500);
            setTimeout(function(){ done(i*2); }.toString()+'(); ',2500);
        }());
    }
    

回答1:

For the initial question on general behaviour:

  • var done = and function done do basicaly the same thing. They will shadow the outer definition in the inner scope but they will not replace it on the outer scope.

  • done = will set the corresponding done variable in scope or will create a global variable if such a variable does not exist and the program is not running in strict mode.

  • At a global level, outside any function, var done = and done = should work the same, but they work differently in IE if you try to use the variable in another script tag (stick to var = - its better anyway).

As for the very evil setTimeout and eval questions:

  • Yes, I guess this kind of stuff should be standardized enough to work the same everywhere. I would still test it anyway. (Or you could use a different solution, given how evil eval is)

  • eval runs code in the current scope (using deep black magic to do so). If you want to run code on the global scope you can use new Function instead.

  • In order to have the settimeout run the string in the curent scope you can add the eval yourself:

    var done = function(d){ console.log('outer done', d); };
    
    (function(){
        var done = function(x){ console.log('inner done', x); };
    
        setTimeout(function(){ done(1); }, 200);           //inner done
        setTimeout('done(2)', 400);                        //outer done
        setTimeout(function(){ eval('done(3)'); }, 600);   //inner done
    }());
    
  • Once again, why are you eval-ing things in the setTimeouts? This all sounds profoundly evil!



回答2:

There are differences between var done and done, because the latter implicates window.done and can be deleted therefore.

The statement done = foobar; will overwrite the next "done" variable in the scope chain. If there is a local var, it changes that, if there is a global one, it will overwrite that one, anf if not it will create a new global one. All these will not affect any private variables in other scopes (closures).



回答3:

One note on your first block. When you give a function a name as you have in the first line, that function name is parsed at compile time and available anywhere within the scope. If you simply assign a function to a variable, then that function (i.e., variable) is only available at runtime after the definition, even if you give it a name.

For example:

// this is valid
foo();
function foo(){ console.log("foo"); }

// this throws an error...
bar();
var bar = function (){ console.log("bar"); };

// ...and so does this...
baz();
var bat = function baz(){ console.log("bazbat"); };

// ...and this!
baz();