Why arg1 and arg2 are undefined? [duplicate] - javascript

(() => console.log(arguments))(1,2,3);
// Chrome, FF, Node give "1,2,3"
// Babel gives "arguments is not defined" from parent scope
According to Babel (and from what I can tell initial TC39 recommendations), that is "invalid" as arrow functions should be using their parent scope for arguments. The only info I've been able to find that contradicts this is a single comment saying this was rejected by TC39, but I can't find anything to back this up.
Just looking for official docs here.

Chrome, FF, and node seem to be wrong here, Babel is correct:
Arrow functions do not have an own arguments binding in their scope; no arguments object is created when calling them.
looking for official docs here
Arrow function expressions evaluate to functions that have their [[ThisMode]] set to lexical, and when such are called the declaration instantiation does not create an arguments object. There is even a specifc note (18 a) stating that "Arrow functions never have an arguments objects.".

As noted by Bergi, arrow functions do not have their own arguments variable.
However, if you do want to capture the args for your arrow function, you can simply use a rest parameter
const myFunc = (...args) =>
console.log ("arguments", args)
myFunc (1, 2, 3)
// arguments [1, 2, 3]
Rest parameters can be combined with other positional parameters, but must always be included as the last parameter
const myFunc = (a, b, c, ...rest) =>
console.log (a, b, c, rest)
myFunc (1, 2, 3, 4, 5, 6, 7)
// 1 2 3 [ 4, 5, 6, 7 ]
If you make the mistake of writing a rest parameter in any other position, you will get an Error
const myFunc = (...rest, a, b, c) =>
console.log (a, b, c, rest)
myFunc (1, 2, 3, 4, 5, 6, 7)
// Error: Rest parameter must be last formal parameter

Related

In variadic JavaScript functions, when would one use the arguments object instead of rest parameters?

The arguments object behaves as follows:
function myFunc1(a, b, c) {
console.log(arguments[0]);
// expected output: 3
console.log(arguments[1]);
// expected output: 2
console.log(arguments[2]);
// expected output: 1
console.log(arguments.sort());
// expected output: "VM427:11 Uncaught TypeError: arguments.sort is not a function"
}
myFunc1(3, 2, 1);
Rest parameters behave as follows:
function myFunc2(...args) {
console.log(args[0]);
// expected output: 3
console.log(args[1]);
// expected output: 2
console.log(args[2]);
// expected output: 1
console.log(args.sort());
// expected output: [1, 2, 3]
}
myFunc2(3, 2, 1)
Rest parameters enable the passing of arguments as an actual array, including its prototype methods, rather than the arguments pseudo-array, without them.
Except for compatibility reasons (rest parameters were introduced in ES6), are there cases wherein one would use the arguments object instead of rest parameters?
The only thing that comes to my mind is if you have something like this as the signature function myFunc2(a1, a2, ...args) and you want to pass all arguments to another function:
function myFunc2(a1, a2, ...args) {
// so something based on a1, a2 or args
// pass all arguments to another function
anotherFunc(...arguments);
}
You for sure could write: anotherFunc(a1, a2, ...args);, but maybe anotherFunc(...arguments) expresses more that you are forwarding all arguments of myFunc2

Want to understand code flow of console.log.call.call.call.call.call.apply(a => a, [1, 2]);

I know how call and apply methods works, but coming to this question, it's some what tricky for me to understand the flow. Can someone help me to understand this.
console.log.call.call.call.call.call.apply(a => a, [1, 2]);
First off, note that in JavaScript, functions are objects, and can have their own properties (which you can access with the . notation just like any other object). Of the properties that exist on all functions are .apply and .call, which are themselves functions.
Second, both .call and .apply provide a mechanism to invoke a function with a specified this value. To understand that, this normally refers to whatever is on the left-hand side of the . when you call a function as a method of an object, e.g. when you call foo.bar(1, 2, 3), within the context of bar, this will refer to foo. So it's also possible to use bar.call(foo, 1, 2, 3) or bar.apply(foo, [1, 2, 3]) to achieve a similar effect; in both cases the first argument becomes this.
So basically, the console.log and all the .call's except the last one don't actually matter. The initial part of the code is just trying to apply .call on some function, and could just as easily be replaced with Function.prototype.call.apply
Skipping ahead a bit, a => a is an arrow function, short-hand for function(a) { return a; }. It creates an anonymous function that accepts one argument and returns that same argument as result. Note that this function doesn't actually refer to this so all the previous calls to .call and .apply are pretty much irrelevant.
Last [1, 2] is just an array literal containing two items, 1 and 2 which be unrolled as arguments by .apply.
So breaking it down:
console.log.call.call.call.call.call.apply(a => a, [1, 2]);
Can be reduced to:
Function.prototype.call.apply(a => a, [1, 2]);
Can be reduced to:
var fn = a => a;
fn.call(1, 2);
.call will use its first argument as the this value of the function and pass subsequent values as parameters, and since fn doesn't use this, we can further reduce it to:
var fn = a => a;
fn(2);
Since fn is just a simple identity function, the result is just:
2;
It doesn't do anything, apply will return 1 and 2 as separate values which call won't do anything with since it's not a function. Even if you were to do console.log.call.call(a => a, [1,2]) you wouldn't get anything since the first call returns just the array [1,2] which isn't a function the second call can do anything with...
console.log.call.call./*and so on*/call./*returns nothing eval({1, 2}) =
undefined*/call./*returns {1, 2} up the chain*/apply(a => a, [1,2]);
//You can try this which also won't return anything:
console.log.call([1,2]);
Although oddly enough I was expecting this sort of code to throw an error, which it didn't, it just didn't log or throw an error. So it really doesn't return anything...

Spread operator in front of brackets?

I am reading info about array destructuring and the spread syntax from MDN and I have stumbled upon the following example that left me a bit cold, despite going over the material progressively.
The code giving me trouble is this:
function myFunction(v, w, x, y, z) { }
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);
I get that v==-1; w==0; x==1; and y==2... but what is ...[3]?
The example is from the spread syntax hyperlink above.
The example you've found is a bit contrived, and you probably wouldn't see it in real code. It's just meant to illustrate that the spread argument syntax ... works with any iterable expression, including standard array literals like [1, 2, 3]. z will be 3 because
myFunction(-1, ...args, 2, ...[3]);
is equivalent to
myFunction(-1, ...args, 2, 3);
The ...[ and ] essentially have no effect in this case; the values are pulled out of the array so it's as though you'd just written them directly in the argument list. As another example,
myFunction(-1, ...args, 2, ...[3, 4, 5]);
is equivalent to
myFunction(-1, ...args, 2, 3, 4, 5);
although z would still be 3 (4 and 5 would be ignored because they're unexpected extra arguments).
Let's break this down a bit: the behaviour of the spread/rest syntax ... in an argument list is defined in section 12.3.6.1 "Runtime Semantics: ArgumentListEvaluation" of ECMAScript 6. To paraphrase, it essentially says "when you see ...X in an argument list, evaluate X, then go through the values it contains and add each of them as a separate argument".
So, when JavaScript sees , 3 in an argument list, it says "add 3 to the argument list".
But when JavaScript sees , ...[3] in an argument list, it says "create a new array containing 3, then go through each of its values (only 3) and add them to the argument list".
You're doing the same thing in both cases, but the simpler way is probably faster.

ES6 - Attempting to console.log(arguments.length) [duplicate]

(() => console.log(arguments))(1,2,3);
// Chrome, FF, Node give "1,2,3"
// Babel gives "arguments is not defined" from parent scope
According to Babel (and from what I can tell initial TC39 recommendations), that is "invalid" as arrow functions should be using their parent scope for arguments. The only info I've been able to find that contradicts this is a single comment saying this was rejected by TC39, but I can't find anything to back this up.
Just looking for official docs here.
Chrome, FF, and node seem to be wrong here, Babel is correct:
Arrow functions do not have an own arguments binding in their scope; no arguments object is created when calling them.
looking for official docs here
Arrow function expressions evaluate to functions that have their [[ThisMode]] set to lexical, and when such are called the declaration instantiation does not create an arguments object. There is even a specifc note (18 a) stating that "Arrow functions never have an arguments objects.".
As noted by Bergi, arrow functions do not have their own arguments variable.
However, if you do want to capture the args for your arrow function, you can simply use a rest parameter
const myFunc = (...args) =>
console.log ("arguments", args)
myFunc (1, 2, 3)
// arguments [1, 2, 3]
Rest parameters can be combined with other positional parameters, but must always be included as the last parameter
const myFunc = (a, b, c, ...rest) =>
console.log (a, b, c, rest)
myFunc (1, 2, 3, 4, 5, 6, 7)
// 1 2 3 [ 4, 5, 6, 7 ]
If you make the mistake of writing a rest parameter in any other position, you will get an Error
const myFunc = (...rest, a, b, c) =>
console.log (a, b, c, rest)
myFunc (1, 2, 3, 4, 5, 6, 7)
// Error: Rest parameter must be last formal parameter

MDN bind why concat arguments when calling apply

MDN specifies a polyfill bind method for those browsers without a native bind method: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
This code has the following line:
aArgs.concat(Array.prototype.slice.call(arguments))
Which is passed as the args to the apply method on the function:
fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
However, this line actually repeats the arguments, so that if I called the bind method as:
fnX.bind({value: 666}, 1, 2, 3)
the arguments passed to fnX are:
[1, 2, 3, Object, 1, 2, 3]
Run the following example and see the console output http://jsfiddle.net/dtbkq/
However the args reported by fnX are [1, 2, 3] which is correct. Can someone please explain why the args are duplicated when passed to the apply call but don't appear in the function arguments variable?
The arguments are in two different contexts there. Each time a function is invoked, among other things, an arguments object is set to all the arguments passed (if the arguments is accessed).
The first mention of arguments are the arguments to bind(), which will become initial arguments.
The second mention are the next set of arguments called on the bound proxy function. Because the arguments name would shadow its parent arguments (as well as the this context needing to be separated), they are stored under the name aArgs.
This allows for partial function application (sometimes referred to as currying).
var numberBases = parseInt.bind(null, "110");
console.log(numberBases(10));
console.log(numberBases(8));
console.log(numberBases(2));
jsFiddle.
No. As you log from x, x() arguments: are [1, 2, 3].
From bind2 you console.log(aArgs.concat(Array.prototype.slice.call(arguments)));, where aArgs = Array.prototype.slice.call(arguments, 1). So what else than [1, 2, 3, {value: 666}, 1, 2, 3] do you expect? Those are not the arguments passed to fnX, but those passed to bind: [{value: 666}, 1, 2, 3].
Inside the bound function, the aArgs variable still contains [1, 2, 3], while the arguments now are empty - you did call x().
If you instead check the value of aArgs.concat(Array.prototype.slice.call(arguments)) from within fBound you'll see what you would expect. The key is that arguments refers to the additional arguments called on an already bound function.

Categories

Resources