3

How javascript works, functional programming

 2 years ago
source link: https://www.codesd.com/item/how-javascript-works-functional-programming.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

How javascript works, functional programming

advertisements

In going through some exercises about functional programming, and returning a closure, came across this example, and cannot figure out how it works:

function invoker (NAME, METHOD) {
  return function(target) {
    var targetMethod = target[NAME];
    var args = _.rest(arguments);
    return function() { return targetMethod.apply(target, args);});
  };
};

The test:

var rev = invoker('reverse', Array.prototype.reverse);
var result= _.map([[1,2,3]], rev);

The output should be:

[[3,2,1]]

but i cannot prove it.

Specific questions: Why is args:

0,1,2,3

Why is console.log(arguments):

[object Arguments]

How to print out the result, to see [[3,2,1]]. When I print out "result", I get:

[object Object]


After correcting the issues in the code (missing semicolons or too many) there appear to be a few closures that get created throughout the script's execution.

First:

function invoker (NAME, METHOD) {
  return function(target) {     // In the example this is rev
    // Begin Scope1 (closure)
    var targetMethod = target[NAME]; // NAME is trapped here in Scope1 (defined outside of this function) when the function is executed!
    var args = _.rest(arguments);
    return function() { //
      // Begin Scope2 (closure)
      return targetMethod.apply(target, args); // target and args are trapped here in Scope2 (defined in Scope1's function) when the function is executed!
    };
  };
}

The invoker does nothing until it is called and the first closure (Scope1's that is) does not get created until invoker is actually invoked:

var rev = invoker('reverse', Array.prototype.reverse);

After rev has been initialized by invoker, it has become a variable that contains a function that accepts a single named argument (called target) that when called will look for a function called NAME (in this case 'reverse') on whatever object target is.

When rev is actually called it also returns a function that, when called, will call the target method (reverse in this case) on target (the array passed in). But rev hasn't been called until the next line is run:

var result= _.map([[1,2,3]], rev);

Here is what is happening here: _.map's purpose is to take a list of items and apply a function to each item in this list. The final result will be a new array with the transformed values in it. The line above passes to _.map a list with exactly one item in it; an array. It also passes to _.map a function to transform each item in that list; in this case rev.

So _.map is called and it calls rev on the only item in the list, our [1,2,3] array. The function rev has the effect of returning yet another function that, when called, will remember NAME, target and args. This function now resides inside the first element of the array variable 'result'.

Now for your questions:

The output should be:

[[3,2,1]]

but i cannot prove it.

In the test code there is no output, only a final variable called result. What I think you are looking for is that somewhere in the end there should be a reversed array. You can verify that the original array has been reversed with the following after the call to initialize result:

alert(result[0]().join());

Why is args:

0,1,2,3

args is really a red herring here; _.map passes 3 arguments to its iterator function. The current value (in this case the array [1,2,3], the key or index (in this case 0) and the original list itself. When _.rest is called on arguments, it slices off the first item leaving us with an array containing 0 and [[1,2,3]]. When reverse is called on this array (args) it ends up returning an array that looks like [1,2,3,0] which is these two items reversed. My tests never showed 0,1,2,3. Why is args a red herring here? Because when reverse is called reverse doesn't take any arguments and so args is ignored. If this was a different function on a different object you would probably encounter issues because of the call to _.rest.

Why is console.log(arguments):

[object Arguments]

Because you are basically calling toString() which will print the object's type.

How to print out the result, to see [[3,2,1]]. When I print out "result", I get:

[object Object]

You can use:

console.log(result[0]().join());

UPDATE: Here is the jsbin link with working code: http://jsbin.com/aYECIDo/5/edit?html,css,js,output


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK