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: