how does multiple lambda function work? - javascript

I have found a script example, in it there is a line of code that looks something like this:
fn = (arg1) => (arg2) => {
//do something with arg1 and arg2
}
I am wondering exactly what is happening here, and how would it look as a "normal" function?

fn = (arg1) => (arg2) => {
//do something with arg1 and arg2
}
fn is a name for the first anon function
its basically a function that returns another function
it translated roughly to
var fn = function(arg1){
return function(arg2){
... // do something
}
}
noting that the this value will differ because it is an arrow function .

It looks like two nested function, where the outer function returns the inner function with a closure over arg1.
var fn = function (arg1) {
return function (arg2) {
//do something with arg1 and arg2
};
};
var fn = function (arg1) {
return function (arg2) {
return arg1 + arg2;
};
};
var add4 = fn(4),
add20 = fn(20);
console.log(add4(5)); // 9
console.log(add20(5)); // 25
Arrow function:
An arrow function expression has a shorter syntax than a function expression and does not bind its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.

I cannot add comments so I write this as an answer. Your example is also known as currying a concept that allows you to pass in a subset of arguments to a function and get a function back that’s waiting for the rest of the arguments.

Related

How to convert a list into multiple arguments in javascript

For example,
var listToBecomeArguments = ["foo","bla"];
myFunc(listToBecomeArguments);
when called would do something like this:
function myFunc(arg1, arg2) {
// arg1 is "foo", arg2 is "bla"
}
For your function
function myFunc(arg1, arg2) {...}
use the .apply() method like this:
myFunc.apply(null, listToBecomeArguments);
and it will do the same as this:
myFunc(listToBecomeArguments[0], listToBecomeArguments[1],...);
You could use local variable arguments to do what you want.
function myFunc() {
console.log(arguments);
}
myFunc("param1", "param2");
// Output:
// > ["param1","param2"]
Quoting the MDN article above, arguments is
an Array-like object corresponding to the arguments passed to a function.

What is fn.bind.apply(fn, arguments) doing?

I saw this shortcut given as an answer on a code Kata but I am having difficulty understanding exactly what the below example is doing.
function func(fn) {
return fn.bind.apply(fn, arguments);
}
So far my understanding is that bind creates a new function similar to doing the following:
function func(fn) {
return function () {
return fn.apply(fn, arguments);
};
}
Is this the case? Any clearer answers or breakdowns of what is going on would be great.
fn.bind
is just
Function.prototype.bind
So we're applying bind to fn, returning
fn.bind(arguments[0]/* doesn't matter, it's fn*/, arguments[1], arguments[2], etc.)
So the bound function is called with arguments being the arguments of func after fn.
Another way to write it would have been:
function func(fn) {
var args = [].slice.call(arguments, 1);
return function () {
var localArgs = [].slice.call(arguments);
return fn.apply(fn, args.concat(localArgs));
};
}
The fact that the context of the call is the initial function (arguments[0]) is most certainly only a side effect. The important thing is we wrap the arguments with the function, but make it possible to dynamically pass other arguments.
Example 1, wrapping all arguments :
function add(a,b){
return a+b
}
var f = func(add, 2 ,3); // f is a function which will always apply add to 2 and 3
console.log(f()) // logs 5
Exemple 2, currying:
function multiply(a,b){
return a*b
}
var multBy2 = func(multiply, 2);
console.log(multBy2(3)) // logs 6

Binary function equivalence - demethodize

I was watching a Pluralsight video from Douglas Crockford: http://pluralsight.com/training/Courses/TableOfContents/javascript-good-parts
In this video he goes through a number of interesting exercises to demonstrate some javascript principals.
When he gets to the 'demethodize' function you basically have the following code sample:
function add(x,y){
return x + y;
}
//add(1,2) => 3
function methodize(fn){
return function(x){
return fn(this, x);
};
};
Number.prototype.Add = methodize(add);
//(1).Add(2) => 3
function demethodize (fn){
return function(x,y){
return fn.call(x,y);
};
}
var newAdd = demethodize(Number.prototype.Add);
// newAdd(1,2) => 3
Note that this 'demethodize' function is for binary functions only.
My question is that, according to my understanding, the following should result in an equivalent 'demethodise' functions:
function demethodize (fn){
return fn.call;
}
or
var demethodize = Number.prototype.Add.call;
But these functions do not work (given the same binary function requirement)!
Why is this?
Please help me fill the gap in my understanding.
I had thought that if I had a binary function whose implementation contained another binary function call with the same arguments passed to the inner function, then using the inner function call directly would be equivalent.
The result of your demethodize function is the Function.prototype.call function - not bound to your fn, i.e. with no this value (which it had if it was called as fn.call(…)). You can however use the bind method to fix that:
function demethodize(fn) {
return Function.prototype.call.bind(fn);
}
// or long:
function demethodize(fn) {
return function(context/*, args... */) {
var args = Array.prototype.slice.call(arguments, 1);
return fn.apply(context, args);
// equivalent (for binary functions) to
return fn.call(context, args[0]);
// ^^^^^^ is a method invocation here
};
}
Because call doesn't know on which function it is supposed to be called. Have a look at the MDN documentation for how this works.
It's the same as
var foo = {bar: function() { console.log(this); }};
foo.bar(); // logs foo
var bar = foo.bar;
bar(); // logs window
You changed the way how .call is executed and with that you changed what this refers to.

Where do function arguments exist when using .call()/.apply()?

i came across a situation where I need to call another function with .call() or .apply() like this:
function b() {
alert(arg);
}
Then
function a(arg) {
b.call();
}
a(123);
Function b is called, but doesnt' have access to arg. That's ok, I can pass scope.. yes?
function a(arg) {
b.call(this);
}
a(123);
Still no - I can't access arg from function b. How can I do it?
UPDATE:
I do not want to modify b function :-)
You still need to pass the arguments via call (individually) or apply (as an array):
function a(arg1, arg2, arg3) {
b.call(this, arg1, arg2, arg3);
// or
b.apply(this, arguments)
// or
b.apply(this, [arg1, arg2, arg3]);
}
Of course, nothing about your situation suggests actually using call or apply: Just invoke the function yourself.
function a(arg) {
b(arg);
}
It’s not possible to “pass scope” or something like that. The scope of a function is determined when the function is created, so it can only access arg if it exists where b is defined.
If arg was part of this, then you could do this using call, i.e. make the this in b the same this as it is in a (of course this will modify whatever this actually refers to, which can have side effects you might not want to happen).
function a (arg) {
this.arg = arg;
b.call(this);
}
function b () {
console.log(this.arg);
}
The other way would be to just pass the argument to b as an actual function argument. You can access all arguments of a function using arguments:
function b () {
console.log(arguments);
}
Try this one:
function a(arg) {
b.apply(this, [arg]);
// or
// b.call(this, arg);
}
function b() {
alert(arguments);
}
You failed to pass the arguments when you called b.
Function::call allows you to pass a fixed number of arguments:
function a(arg1,arg2) {
return b.call(this,arg1,arg2);
}
Function::apply allows you to pass any number of arguments, as an array:
function a(arg1,arg2) {
return b.apply(this,[arg1,arg2]);
}
// or
function a(arg1,arg2) {
return b.apply(this,arguments); // The magical 'arguments' variable
}
this is the context object, and is not the same thing as scope.
I'll guess the problem lies in b(). There's no 'arg' argument defined. Try:
function b(arg) { alert(arg); }
and
function a(arg) {
b.call(this,arg);
}
a(123);
now it runs
(Update: the call needs the arguments ( context functionarg1, functionarg2...) )
Assuming that, for some reasons you can't modify the body of b , you can try something like this:
function a(arg) {
eval("("+ b.toString() +")()");
}
DEMO

How do I pass a function(delegate?) as a parameter to another function in Javascript and then use it

I want to pass a function to another function. I think functions being passed like that are call delegates? I am having a hard time finding a good explanation for this kind of thing online. Is this the right way to do this?
function getCellContentByColumnIndex = function(row, index) {
return $(row.children().get(index)).text();
}
function naturalSort(a, b, func) {
//...
var $a = func(a);
var $b = func(b);
//...
}
//usage
naturalSort(x, y, getCellContentByColumnIndex);
Your code:
function getCellContentByColumnIndex = function(row, index) {
return $(row.children().get(index)).text();
}
Is a syntax error. The following is a function declaration:
functon foo() {}
And this is a function expression:
var foo = function(){}
And this is a named function expression:
var foo = function bar(){}
There are a number of answers here on the differences, there is a detailed explanation in the article Named function expressions demystified which also covers many other aspects of function declarations and expressions.
The term "anonymous function" is jargon for a function expression that has no name and isn't assigned to anything, e.g.
someFn( function(){...} )
where someFn is called and passed a function that has no name. It may be assigned a name in someFn, or not. Ic could just be referenced as arguments[0].
Passing a function is not delegating, that is jargon for the practice of putting a listener on a parent element and catching bubbling events, it is preferred in cases where it can replace say a click listener on every cell in a table with a single listener on the table.
Anyhow, passing a function is just like passing any other object:
function foo(){
alert('foo');
}
function callIt(fn) {
fn();
}
callIt(foo); // 'foo'
In the above, foo is passed to callIt and assigned to the local variable fn, and is then called.
You pass functions around as variables like so:
var getCellContentByColumnIndex = function(row, index) {
return $(row.children().get(index)).text();
}
function naturalSort(a, b, func) {
//...
var $a = func(a);
var $b = func(b);
//...
}
//usage
naturalSort(x, y, getCellContentByColumnIndex);
This is called using anonymous functions.
Anonymous functions..
var getCellContentByColumnIndex = function(row, index) {
return $(row.children().get(index)).text();
}
will work..rest stuff of calling is already perfect in your code..:)
In JavaScript, functions are treated as first class citizens which mean you can toss them here and there like simple variables. The key is, use the FunctionName when you want to refer to function and use FunctionName() to invoke it.
this line: naturalSort(x, y, getCellContentByColumnIndex);
could have been written as
naturalSort(x, y, function (){
return $(row.children().get(index)).text();
});
In which case it would have been called passing Anonymous Function

Categories

Resources