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.