Javascript: Re-assigning a function with another function

closures, function, javascript, pass-by-reference

Solution

The assignment to the `fn` argument just makes that identifier to point to the anonymous function, `foo` in the outer scope is not affected.

When you pass an object as an argument, one can say "references are passed by value". The assignment just replaces the location where the `fn` identifier refers to.

That's how the evaluation strategy works in JavaScript.

Just before the assignment in the `fnChanger` functions, the two identifiers, the global `foo` and the `fn` argument, point to the same function object:

                ---------------------------------------------
    foo ----->  |function foo { sys.print('Un changed!'); } |
                ---------------------------------------------
                   ^
                   |
    fn -------------

After the assignment, `fn` will simply point to the new function:

                ---------------------------------------------
    foo ----->  | function foo { sys.print('Unchanged!'); } |
                ---------------------------------------------

                ---------------------------------------
    fn ------>  | function { sys.print('Changed!'); } |
                ---------------------------------------

How could you change it?

Well, assuming that `foo` is a function in the global scope, you could do something like this:

function fnChanger(obj, name) {
    obj[name] = function() { sys.print('Changed!'); };
}

function foo() {
    sys.print('Unchanged');
}

fnChanger(this, 'foo');
foo(); // Changed!

The above will work because in the `fnChanger` function, we require a base object and a property name, functions declared in the global execution context are bound as properties of the Global object, therefore we can re-assign its value in that way.

The line `fnChanger(this, 'foo');` should be executed also in the Global scope, it will pass the `this` value (which refers to the Global object in this scope) and a property name, allowing you to make an assignment to the `GlobalObject.foo` identifier.

If that code were inside a function, there is no way we can get a base object, because in this "Function Code Execution Context", function declarations (variable declarations and function formal parameters also) are bound as properties of a non-accessible object, called the Variable Object (a chain of these Variable Objects, forms the Scope Chain), and if it were the case, the only workaround would be to use `eval`.

More info:

- ECMA-262-3 in detail. Chapter 8. Evaluation strategy.

Problem

Let's say I have these two functions: ``` function fnChanger(fn) { fn = function() { sys.print('Changed!'); } } function foo() { sys.print('Unchanged'); } ``` Now, if I call `foo()`, I see `Unchanged`, as expected. However, if I call `fnChanger` first, I still see `Unchanged`: ``` fnChanger(foo); foo(); //Unchanged ``` Now, I assume this is because `foo` is not being passed to `fnChanger` by reference, but I may be wrong. Why does `fnChanger` not change `foo` to print `Changed!`? Furthermore, how can I get `fnChanger` to change `foo` without too much messy syntax? PS: I'm using node.js to test all this stuff, so that's where the `sys.print` comes from.

Original source