Why is it necessary to pass existing arguments to `setTimeout` again? - javascript

Why is it necessary to write a and b after mls in the setTimeout method here? Aren’t a and b already defined in the arrow function?
function f(a, b) {
alert(a + b);
}
// shows 3 after 1 second
Function.prototype.defer = function(mls) {
return (a, b) => setTimeout(this, mls, a, b);
}
f.defer(1000)(1, 2);

Because f.defer(1000) returns the arrow function which in turn gets called with (1,2) as parameter. This arrow function is calling setTimeout which is supposed to call the same function f with these parameters 1 and 2. And the definition of seTimeout states that you can pass parameter to the callback function after first 2 parameters. Please refer below definition and link for the reference.
window.setTimeout(function[, delay, param1, param2, ...]);
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout

The arrow function is defining a function that then invokes setTimeout(this, mls, a, b). It could also be written as:
Function.prototype.defer = function(mls){
var that = this;
return function(a,b) {
setTimeout(that, mls, a, b);
}
}
This is important to note because you're actually returning a function from defer. So when you call f.defer(1000), the return value is a function - your arrow function, to be specific - and then you invoke that function with the values 1 and 2 when you call f.defer(1000)(1, 2);.
If you don't, your function will not be called with any parameters. These parameters are passed into the originally invoked function.

setTimeout takes a variable number of arguments. The first one is the function (this, or f in this case), the second one is the delay. Any argument after that is passed to the to-be-called function upon calling it.
Your function f expects two arguments; if they aren’t passed, they are undefined. There are indeed an “a and b already defined in the arrow function”, but they are scoped to the arrow function. If a function calls another function, its arguments aren’t automatically transfered.
Internally, setTimeout is doing something like outerWorking in this example:
const inner = (a, b) => a + b,
outerWorking = (a, b) => inner(a, b),
outerNotWorking = (a, b) => inner();
console.log(outerWorking(2, 3)); // 5
console.log(outerNotWorking(2, 3)); // NaN
So f.defer(1000) returns a new function with mls === 1000 and this === f. It accepts a and b which are yet to be defined with the next function call (calling the arrow functions, with the argument list (1, 2)). Only when you pass a, b at f.defer(1000)(1, 2), then setTimeout(this, mls,a,b) will be called with a === 1, b === 2 and the other two bindings above (this and delay).
Alternatively, this could be written as
Function.prototype.defer = function(mls, a, b){
setTimeout(this, mls, a, b);
};
f.defer(1000, 1, 2)
But there’s an advantage in the original, curried approach, as you can simply detach the “defered function” from the final call:
const add1sDelay = f.defer(1000);
add1sDelay(1, 2);

Related

Find which parameters a higher order function contains

I have a function that accepts a function as an argument.
This callback function can receive up to 5 parameters. Any of these can be null at some point.
I tried accessing the arguments property, but it throws this error:
'caller', 'callee', and 'arguments' properties may not be accessed on strict mode.
Is it possible to find which arguments this function received? So i don't have to pass it all 5 each time?
function bar(callback){
// do some stuff
return callback(first, second, third, fourth, fifth)
}
Some use cases I'm having:
bar((a, b, c) => a + c)
bar((a, b, c, d) => a + c + d)
bar((a, b, c, d, e) => a + b + e)
I'm always calling the callback with 5 arguments, but sometimes, not all of them are being used. And for each one, I'm doing some computation.
Another example:
If I call the function like this:
bar((a, b, c, d, e) => a + b + e)
And my function defined like this:
function bar(callback){
// do some stuff with
return callback(first, second, third, fourth, fifth)
}
There would be no need for me to pass the third and fourth parameters to the callback, because they are null. But since I don't have access to the arguments the callback has received, I'm not being able to do this.
You could use Function.length,
function func1() {}
function func2(a, b) {}
console.log(func1.length);
// expected output: 0
console.log(func2.length);
// expected output: 2
But, I would not advice writing code that relies on this. The callback function could be implemented in different ways that this wouldn't work. Some examples:
function callback(){
console.log(arguments); // could access all parameters but length is 0
}
function callback(...args){
console.log(args); // could access all parameters but length is 0
}
function callback(a,b=0,c,d,e){
console.log(a,b,c,d,e); // could access all parameters but length is 1
// 1, only parameters before the first one with
// a default value is counted
}
A better solution would be not overloading the function with different behaviors depending on what the callback expects, and actually tell what you should "return" to the callback
function bar(callback, n){
if(n===0) // do something
else if(n===1) // do something else
}
Or don't write "overloaded" functions that have multiple behaviors, and actually having multiple functions:
function foo(callback){
// do some sutff
return callback(first, second)
}
function bar(callback){
// do some sutff
return callback(first, second, third, fourth, fifth)
}
EDIT: from your last edit you should need to have something like this
function bar(params, callback) {
const obj = {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5
};
const args = params.map(p => obj[p]);
return callback.apply(this, args);
}
console.log(bar(['a', 'b'], (a, b) => a + b)) //3
console.log(bar(['a', 'd', 'e'], (a, d, e) => a + d + e)) //10
You could take the Function#length property of the function, which returns the number of defined parameters.
function bar(callback) {
console.log(callback.length);
}
bar((a, b) => a + b);
bar(function (a, b, c) { console.log(a, b, c); });

How to pass a function with arguments to a function as argument in javascript? [duplicate]

This question already has answers here:
Passing a function with parameters as a parameter?
(7 answers)
Closed 3 years ago.
I'm new to javascript and I was learning higher-order functions where I learned about passing functions as arguments to other functions. How can I pass a function with arguments to a function?
I want to pass the function's arguments when passing the function as parameter to the main function.
example :
function fubar(a,b,fun(c,d)){
//execute here
}
and not like this
function fubar(a,b,fun()){
fun(a,b)
}
Here's an example, just pass it like a regular argument, no specific syntax is required :)
// define the function argument like a regular argument
function fubar(a, b, fn){
// call that argument like a function
return fn(a, b);
}
// sample function
function add(c, d){
return c + d;
}
// pass the "add" function like a regular argument
let result = fubar(1, 2, add);
console.log(result);
You just need to pass the name of the function as the parameter, just like another variable.
for example :
foobar(5, 10, baz, ham);
function foobar(a, b, fn1, fn2){
...
fn1(); // call the baz function.
res = fn2(a,b); // calls ham func with a and b as parameter
console.log(res)
...
}
function baz(){
console.log("Inside the Baz function ");
}
function ham(s,t){
console.log(s, t);
return s+t;
}
If you're asking how to pass a function that will execute with some pre-determined arguments, you can do so using another function.
For example
const a = 'a'
const b = 'b'
const c = 'c'
const d = 'd'
function fubar(a, b, fn) {
console.info('func:', a, b, fn()) // executing "fn()" here
}
function fun(arg1, arg2) {
console.info('fun:', arg1, arg2)
return 'return value from fun' // just an example so you can see it in fubar()
}
fubar(a, b, () => fun(c, d))
Here, () => fun(c, d) is an self-contained, anonymous arrow function (or "lambda") that when called, will execute fun(c, d).

Can someone explain this "passing arguments" in javascript example?

I'm reading through Javascript Garden, and I'm trying to wrap my head around the following example:
Passing Arguments
The following is the recommended way of passing arguments from one function to another.
function foo() {
bar.apply(null, arguments);
}
function bar(a, b, c) {
// do stuff here
}
Another trick is to use both call and apply together to create fast, unbound wrappers.
function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
// Create an unbound version of "method"
// It takes the parameters: this, arg1, arg2...argN
Foo.method = function() {
// Result: Foo.prototype.method.call(this, arg1, arg2... argN)
Function.call.apply(Foo.prototype.method, arguments);
};
I'm trying to figure out two things:
1) What exactly is an "unbound wrapper"?
2) How does the chaining from .call to .apply work and/or make the code faster?
"1) What exactly is an "unbound wrapper"?"
Unbound wrapper is just a function that calls another function by passing on the desired this value and arguments.
"2) How does the chaining from .call to .apply work and/or make the code faster?"
The .call.apply() is faster than having to do a .slice() on the arguments to separate the this from the actual args.
Otherwise it would need to do this, which is slower:
Foo.method = function(ths) {
Foo.prototype.method.apply(ths, Array.prototype.slice.call(arguments, 1));
};
What exactly is an "unbound wrapper"?
A function that is not to be called on an instance, but with an instance as its argument. It's not bound to the prototype / doesn't need to be bound to an instance. Example:
var x = new Foo;
// instead of
x.method(1, 2, 3);
// you now call
Foo.method(x, 1, 2, 3);
The benefit of this is that you can pass the function around without caring about its this context.
How does the chaining from .call to .apply work and/or make the code faster?
It doesn't really make anything "faster". It's not even compared to any "slower" solution.
For how it works, please check the duplicate question What's the meaning to chain call and apply together?.
I think the code should be like this:
function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
Foo.method = function() {
//Notice this line:
Function.apply.call(Foo.prototype.method, this, arguments);
};
then
Foo.method(1,2,3) => function Foo() {} 1 2 3
Other examples:
Function.apply.call(Array,this,[1,2]) => [1, 2]
Function.call.apply(Array,this,[1,2]) => [window]
Function.call.call(Array,this,[1,2]) => [[1, 2]]

What is the purpose using a named function when assigning to a variable in JavaScript?

I recently came across this pattern in the source for https://github.com/yeoman/generator-webapp:
AppGenerator.prototype.packageJSON = function packageJSON() {
this.template('_package.json', 'package.json');
};
What's the purpose of giving the function the name "packageJSON" when you're going to assign it to a variable or object property anyways? I've always used anonymous functions in similar cases.
For debugging purposes. If you use a named function you can see that name in the call stack trace in your favorite dev tools. Otherwise you'd see anonymous function.
That's called a named function expression (or NFE) and it makes the debugging process much easier.
An important detail to remember is that this name is only available in
the scope of a newly-defined function; specs mandate that an
identifier should not be available to an enclosing scope:
var f = function foo(){
return typeof foo; // "foo" is available in this inner scope
};
// `foo` is never visible "outside"
typeof foo; // "undefined"
f(); // "function"
As others says, for debugging purposes mainly. But not only that. For instance, you can rely on the fact that in function's body, you can access to the function itself using the name you set. To give a silly example:
var sum = function (a, b) {
if (a < 3)
return sum(3 + a, b);
return a + b;
}
sum(1, 2) // 3;
But let's see what happens now:
var aSum = sum;
sum = null;
aSum(1, 3); // TypeError: sum is not a function
Naming the function, will cover that use case:
var sum = function sum(a, b) {
if (a < 3)
return sum(3 + a, b);
return a + b;
}
sum(1, 2) // 6
var aSum = sum;
sum = null;
aSum(1, 2) // 6
That's because in the body of the function, the name of the function is always referring to it, and is not taken from another scope, like the first example.

I'm reading Eloquent Javascript and I am a little confused by this partial function example. Please help explain

function asArray(quasiArray, start) {
var result = [];
for (var i = (start || 0); i < quasiArray.length; i++)
result.push(quasiArray[i]);
return result;
}
function partial(func) {
var fixedArgs = asArray(arguments, 1);
return function(){
return func.apply(null, fixedArgs.concat(asArray(arguments)));
};
}
function compose(func1, func2) {
return function() {
return func1(func2.apply(null, arguments));
};
}
var isUndefined = partial(op["==="], undefined);
var isDefined = compose(op["!"], isUndefined);
show(isDefined(Math.PI));
show(isDefined(Math.PIE));
Why can't the function compose simply return:
func1(func2);
and give the proper output. I thought the partial function which is stored in the variable isUndefined already returns func.apply(null, [fixed, arguments])
var op = {
"+": function(a, b){return a + b;},
"==": function(a, b){return a == b;},
"===": function(a, b){return a === b;},
"!": function(a){return !a;}
/* and so on */
};
Both partial and compose are higher-order functions.
isUndefined will return a function that, when invoked, will invoke the originally passed function with the original arguments plus any new arguments passed at invocation.
To answer your question, you'd be calling apply on the function returned from partial which will in turn, call apply on the function originally passed to partial.
You want compose to return a function that when called, will return the result of calling the first function passed the second function as an argument (with the second function passed the arguments passed to the compose invocation). If compose returned func1(func2), then you'd assign the result of the invocation to the variable isDefined.
EDIT:
Now that we have op, let's try to decompose this:
var isUndefined = partial(op["==="], undefined);
this is equivalent to
var isUndefined = partial(function(a, b){return a === b;}, undefined);
isUndefined is assigned a function that, when called, will call the function passed as the first argument to partial, passing in undefined as the first argument to that function call, followed by the arguments passed to the function isUndefined i.e.
partial(function(a, b){return a === b;}, undefined /* this will become 'a' when isUndefined is invoked */)(argumentForisUndefined /* this will become 'b' when isUndefined is invoked */);
isDefined composes isUndefined with another function that negates the result of isUndefined.
var isDefined = compose(op["!"], isUndefined);
is equivalent to
var isDefined = compose(function(a){return !a;}, isUndefined);
which is equivalent to (renamed variables for clarity)
var isDefined = compose(
function(a){return !a;},
partial( /* partial function becomes 'a' passed to first function */
function(b, c) {
return b === c;
},
undefined /* undefined becomes 'b' passed to partial */
)
)(argumentForisDefined /* argumentForisDefined becomes 'c' passed to partial */);
If we look at what we have so far and substituting for readability, boils down to a function that takes an argument and compares it to undefined, negates the result and returns a boolean
var isDefined = function (b) { return !undefined === b; }
So lets simply dissect it. Assuming we have this compose function:
function compose(func1, func2) {
return func1(func2.apply(null, arguments));
}
What will happen when you use it like this?
a = compose(function(){console.log(1)}, function(){console.log(2)});
The second function would be call immediately outputting 2, and straight afterwards the first function will be called outputting 1. a will be undefined, because the first function does not return anything.
What you want combine to do, is to return a new function, that combines the two other functions and that you can call at will.
Doing the above all on the original compose, will return a new function, that, when you call it with a() will output 2 and then 1.

Categories