Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript: Re-assigning a function with another function

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.

like image 212
Austin Hyde Avatar asked Oct 26 '10 00:10

Austin Hyde


People also ask

How to call a function that returns another function in JavaScript?

- GeeksforGeeks How to call a function that return another function in JavaScript ? The task is to call a function which returns another function with the help of JavaScript. we’re going to discuss few techniques. First call the first function-1. Define a function-2 inside the function-1. Return the call to the function-2 from the function-1.

Why can't I get the result of a function in JavaScript?

In Javascript, functions are first class objects that can be treated just as another variable. But for the function to return its result, it has to be first invoked. When you are invoking the fnChanger (foo), the fn variable actually gets overridden with foo (). But you are not getting the result because that function was never invoked.

How do you call a function from another function in Python?

To call a function inside another function, define the inner function inside the outer function and invoke it. When using the function keyword, the function gets hoisted to the top of the scope and can access any of the available variables in the scope.

Can you pass a function into the arguments of a function?

Since functions can be passed around anywhere, we can pass them into the arguments of functions. My first hands-on experience with anything having to do with programming in general was getting started with writing code in JavaScript, and one concept in practice that was confusing to me was passing functions into other functions.


1 Answers

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.
like image 93
Christian C. Salvadó Avatar answered Oct 07 '22 00:10

Christian C. Salvadó