Alan
Alan

Reputation: 46833

Consequences of Dynamically rewriting a function in javascript?

In javascript, you can rewrite a function, like so:

function foo() { 
   setTimeout(function() {
        alert('sup stallion');
        foo = function() { //rewrite foo to nolonger wait 4 seconds to alert.
             alert('sup stallion');
        }
   }, 4000);
}

Obviously this is a contrived example, but is there anything conceptually wrong with this approach (other than a race condition).

Upvotes: 7

Views: 1933

Answers (3)

bfavaretto
bfavaretto

Reputation: 71918

One thing I noticed while testing your code. Consider this:

setInterval(foo, 6000);

Function foo is being passed to setInterval before it was modified, and the original foo will run every 6 seconds, even after the binding has been updated.

On the other hand, the code below will run the original function only on the first call (which updates the binding). Subsequent calls will invoke the updated version:

setInterval(function(){foo();}, 6000);

Looks obvious, but could be hard to debug...

Upvotes: 4

zzzzBov
zzzzBov

Reputation: 179086

Dynamic function rewriting can be used as a form of lazy initialization, however there is a catch:

function Foo() {...}
Foo.prototype = {
    bar: function () {
        //some initialized variables to close over
        var a, b, c, ...;
        Foo.prototype.bar = function () {
            //do stuff with variables
        };
        Foo.prototype.bar.call(this);
    }
};

While this code is relatively straight-forward to understand, and would be used as:

var f = new Foo();
f.bar(); //initializes `bar` function
f.bar(); //uses initialized `bar` function

it has a hidden issue:

var f = new Foo(),
    g = {};
//passing by reference before the function was initialized will behave poorly
g.bar = f.bar;
f.bar(); //initializes `bar` function
g.bar(); //re-initializes `bar` function
f.bar(); //uses initialized `bar` function
g.bar(); //re-initializes `bar` function

It's for this reason that any initialization needed for a function is typically done using a module pattern:

function Foo() {...}
Foo.prototype = {
    bar: (function () {
        var a, b, c, ..., fn;
        //some initialized variables to close over
        fn = function () {
            //do stuff with variables
        };
        return fn;
    }())
};

The module pattern has the disadvantage of calling the initialization code immediately, but wont have the issues associated with the function reference.

Upvotes: 3

Guffa
Guffa

Reputation: 700372

Self modifying code can be confusing, and hard to debug, so it's generally avoided.

Other than that there is no problem, and no race condition either.

Upvotes: 7

Related Questions