I'm writing a function that checks if arguments are zero, and it doesn't seem to work correctly. Note: Using Chrome as my browser, but this code should be cross-browser supported.
// check all arguments, and make sure they aren't zero
function zeroCheck(arg1, arg2) {
var i, argsLen = arguments.length;
for (i = 0; i <= argsLen; i += 1) {
if (arguments[i] === 0) {
// This is where it doesn't behave as I expected
arguments[i] = 1; // make arg1 = 1
}
}
console.log(arg1); // arg1 = 0
}
zeroCheck(0, 2);
I was expecting arg1 to be equal to 1, but it is still equal to 0.
From the ECMA-262 spec:
"For non-strict mode functions the array index (defined in 15.4) named data properties of an arguments object whose numeric name values are less than the number of formal parameters of the corresponding function object initially share their values with the corresponding argument bindings in the function’s execution context. This means that changing the property changes the corresponding value of the argument binding and vice-versa. This correspondence is broken if such a property is deleted and then redefined or if the property is changed into an accessor property. For strict mode functions, the values of the arguments object‘s properties are simply a copy of the arguments passed to the function and there is no dynamic linkage between the property values and the formal parameter values."
But if you read the technical details of how the arguments object is set I think you'll find it is based on how many arguments are actually passed to the function when it is called, not how many named arguments are declared, so using arguments and a loop to check the value of each named parameter might not work if they're not all passed in. Though in your case if you're testing specifically for 0 it should work since parameters that are not passed will be undefined rather than 0.
Having said that, exactly how the arguments object actually behaves depends on the browser. Chrome doesn't follow the spec.
Though some browsers appear to work the way you want (Chrome and Firefox), it isn't obvious to me from the ECMAScript spec that it will always be this way. It makes it sounds like the arguments array is probably just a reference to the named arguments in non-strict mode and it specifically says that the two should have no connection to one another in strict mode (in other words what you want to do is specifically NOT supposed to work in strict mode).
You can see in this jsFiddle http://jsfiddle.net/jfriend00/bG5xp/ that Chrome appears to implement it as the spec describes. There is linkage between arguments[0] and arg1 in non strict mode and there is no linkage between them in strict mode. A careful reading of the spec doesn't say that javascript is required to have linkage between the two in non-strict mode, but it does make it sound like it is likely. If you wanted to rely on that and you were sure you never needed your code to work in strict mode, then you would have to test a bunch of browsers to see if the behavior you desire is widely supported.
It is also not clear from the spec if the arguments array is always meant to be modifiable though that seems more likely given that it's implemented with a javascript object (not an actual array).
The safe way to modify the arguments array is to make a copy first and modify the copy. That will, of course, not modify any named arguments. You could modify those manually if you wanted to.
A common way to make a copy of the arguments array is:
var args = Array.prototype.slice.call(arguments, 0);
One generally uses either the arguments array or the named arguments and not both since any named argument is also in a known position in the arguments array so you don't really need to worry about a named argument changing value when you modify the arguments array.
Try it like this. arg1 with value 0 evaluates to false/falsy, so you can use this shortcut boolean evaluation:
function zeroCheck(arg1,arg2) {
arg1 = arg1 || 1;
console.log(arg1); //=> 1
}
zeroCheck(0,2);
A generic function to check for all arguments (returns an Array)
function zeroCheckArgs(args){
return [].slice.call(args).map(function(a){return a || 1;});
}
//more conservative
function zeroCheckArgsAlt(args){
var retArgs = [];
for (var i=0;i<args.length;i+=1){
retArgs.push(args[i] || 1);
}
return retArgs;
}
function some(){
var args = zeroCheckArgs(arguments);
console.log(args);
}
function someAlt(){
var args = zeroCheckArgsAlt(arguments);
console.log(args);
}
some(1,0,0,12,12,14,0,1); //=> [1, 1, 1, 12, 12, 14, 1, 1]
someAlt(1,0,0,12,12,14,0,1); //=> [1, 1, 1, 12, 12, 14, 1, 1]
It works for me, check this example fiddle
#nnnnnn -
"For non-strict mode functions the array index (defined in 15.4) named
data properties of an arguments object whose numeric name values are
less than the number of formal parameters of the corresponding
function object initially share their values with the corresponding
argument bindings in the function’s execution context. This means that
changing the property changes the corresponding value of the argument
binding and vice-versa. This correspondence is broken if such a
property is deleted and then redefined or if the property is changed
into an accessor property. For strict mode functions, the values of
the arguments object‘s properties are simply a copy of the arguments
passed to the function and there is no dynamic linkage between the
property values and the formal parameter values."
Your citation actually answers my original question. The reason that my code as posted below does not work as expected is because I was actually using "strict" mode.
// check all arguments, and make sure they aren't zero
function zeroCheck(arg1,arg2) {
var i, argsLen = arguments.length;
for (i = 0; i <= argsLen; i += 1) {
if (arguments[i] === 0) {
// This is where it doesn't behave as I expected
arguments[i] = 1; // make arg1 = 1
}
}
console.log(arg1); // arg1 = 0
}
zeroCheck(0,2);
It worked in for xdazz, Jeroen Moons, and jFriend00 - because they did not include the strict:
http://jsfiddle.net/nSJGV/ (non-strict)
http://jsfiddle.net/HDjWx/ (strict)
Related
I’d like to know both for regular all-in-the-family JS developer-defined functions, as well as predefined DOM methods: what happens if I try to call IE’s attachEvent with the signature of the WHATWG’s addEventListener? For instance:
elem.attachEvent('onbillgates\'mom', function(e){ this.mount(); }, false);
Specifically, note the third argument false. Will that trip anything up, even though the attachEvent method’s signature only calls for two arguments?
What about this example?
function foo(FirstOf2, SecondOf2) {
console.log(FirstOf2 + SecondOf2);
}
foo(1, 2, true);
JavaScript doesn't have the concept of a fixed parameter list. For your own functions you can always specify as many parameters as you want and pass in as many as you want which ever type you want.
For built-in functions, which correlate to native code, it depends.
You asked on what it depends:
Let's look at the ECMA-262
Section 15 about built-in (not to confuse with host) functions in general
Unless otherwise specified in the description of a particular function, if a function or constructor described in this clause is given fewer arguments than the function is specified to require, the function or constructor shall behave exactly as if it had been given sufficient additional arguments, each such argument being the undefined value.
Alright. If I pass in less arguments than needed, it depends on the spec of the function itself (scroll down section 15 to find the spec for each built-in function).
Unless otherwise specified in the description of a particular function, if a function or constructor described in this clause is given more arguments than the function is specified to allow, the extra arguments are evaluated by the call and then ignored by the function. However, an implementation may define implementation specific behaviour relating to such arguments as long as the behaviour is not the throwing of a TypeError exception that is predicated simply on the presence of an extra argument.
Passing in too many arguments should never raise a TypeError. But still it may raise other errors. Again, it depends on the function you talk about.
You were talking explicitly about the DOM and not about built-in functions. To be honest I can't find the corresponding parts of the spec. The ECMA spec is so much easier to read then the w3 website.
Won't hurt. You can even call a function with less parameters than it takes, as long as the function code is ok with a few undefined values.
I came across this important, however old, question; and I hope it'll be beneficial for future generations to share my experiments with it:
One can use the arguments object in order to access a function's arguments, regardless of the amount of arguments in the function's signature.
It's worth mentioning that this doesn't apply to arrow functions:
function singleArg(x) {
console.log(arguments);
}
singleArg(1, 2); // Called with 2 arguments
singleArg(); // Called with 0 arguments
// Results in an error, as 'arguments' isn't defined for arrow functions
((arg) => console.log(arguments))(1);
It's stated in the documentation that arguments isn't exactly an Array:
“Array-like” means that arguments has a length property and properties indexed from zero, but it doesn't have Array's built-in methods like forEach() and map().
Hence the following code results in an error:
(function singleArg(x) {
console.log(arguments); // This line works
arguments.forEach(x => console.log(x)); // This causes an error
})(1, 2);
Upon calling a function with less arguments than in its signature, they're assigned undefined:
(function twoArgs(a, b) {
console.log(`a: ${a}\nb: ${b}`);
})(1);
Try taking a look at this post and perhaps this one.
From MDN:
The arguments object is a local variable available within all
functions; arguments as a property of Function can no longer be used.
You can refer to a function's arguments within the function by using
the arguments object. This object contains an entry for each argument
passed to the function, the first entry's index starting at 0.
You can use the arguments object if you call a function with more
arguments than it is formally declared to accept. This technique is
useful for functions that can be passed a variable number of
arguments.
function myConcat(separator) {
var result = "";
// iterate through non-separator arguments
for (var i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}
I don't think it will mess anything up unless you are explicitly dealing with the implicit arguments array. Why are you doing this though?
I'm currently studying javascript by following the "you dont know js" series.
In section "this & object prototype", the author came up with an way to soft bind this.
However, I am extremely confused by the code. So I was wondering if someone could kindly explain it to me, steps by steps, what the code really does?
//step 1: if "softBind" property does not exist on `Function.prototye`
if (!Function.prototype.softBind) {
//step 2: create a property named "softBind" on "Function.prototype" and assign to "softBind" the following function
Function.prototype.softBind = function(obj) {
//step 3: what is the point of assigning "this" to the variable "fn"?
//what does "this" represent at this point in time?
var fn = this,
//step 4: I understand that "arguments" is an array-like object, i.e. "arguments" is not a true array.
//But you can convert "arguments" to an true array by using "[].slice.call(arguments)".
//The thing I dont understand here is, why the 1?
//I understand it tells "slice" method to start slicing at index 1, but why 1?
//And what is the purpose of "curried" variable?
curried = [].slice.call( arguments, 1 ),
bound = function bound() {
//step 5: I understand what "apply" function does
return fn.apply(
//step 6: I dont really understand how "!this" works.
(!this ||
//step 7: utterly confused...
(typeof window !== "undefined" &&
this === window) ||
(typeof global !== "undefined" &&
this === global)
//step 8: if the above statements evaluates to "true", then use "obj",
//otherwise, use "this"
) ? obj : this,
//step 9: can't I write "curried.concat(arguments)" instead?
//why the convoluted syntax?
curried.concat.apply( curried, arguments )
);
};
//step 10: Why assign the "fn.prototype" as the prototype to "bound.prototype"?
bound.prototype = Object.create( fn.prototype );
return bound;
};
}
I'm very sorry for the long question, but I thought instead of dividing the question into several posts, it is more convenient if they are put into one place.
step 3: what is the point of assigning "this" to the variable "fn"?
The value of this holds a pointer to the currently executing function object. Only function objects can be held, so only things actually created through new() or equivalent notation. This can be useful for passing a reference to an outer object to an inner object created within said outer object.
Here's a minimal example:
function fn1() {
var x = this; // x = fn1.
this.u = 5;
function fn2() {
this.u = 10;
console.log(this.u); // Prints the member of fn2.
console.log(x.u); // Prints the member of fn1.
};
var W = new fn2();
}
var V = new fn1();
The output should be:
10
5
First, an object of type fn1 is created called V. It has a member variable u holding the value 5. Then, we create an object of type fn2 called W within fn1. It also has a member variable u, but here it holds the value 10. If we wanted to print the value of V.u within W, then we need a pointer to V. Calling this.u within W would output its u value (10), which is not what we want. So we define a variable x within the scope of the class fn1, holding the this pointer for us. Now it's possible to access the members of fn1 within fn2.
Step 4
The first argument is the object being bound to. You don't want to pass that to the function being bound, that would break its functionality, for it does not expect an extra argument prepended to its normal list of arguments. So, the first argument has to be removed.
step 6: I dont really understand how "!this" works.
!this is simply a way of checking whether this is defined. If it is not, then the value will be true. Otherwise, since this
would be an object (which evaluate to true when cast to a boolean), then it is false.
step 7: utterly confused...
Here, the original author checks if this is equal to either window, or global. Note; In modern browsers, checking for just window is enough, but IE exists (as do non-browser javascript environments). So, the full statement evaluates to this thing:
If I am not called from within an object, or if I'm called from the object window or global, then return the object softbind was created with. Otherwise, return the object I was called from
Note that this is exactly what the author of the original article wants. When a library function is called with this special binding, then we can be sure that whatever the library does; it can't access the global context through the use of the this variable. But, it can access any other object, allowing you to interface with the library.
step 9: can't I write "curried.concat(arguments)" instead?
Curried holds all arguments the original softbind function was called with, except for the first argument. arguments , at this point, is not equal to arguments in the earlier call. Here, it refers to the arguments the bound function is called with, not those it was bound with. This line integrates the two sets of arguments, allowing you to provide default arguments. The trick used here is to concatenate the arguments, e.g. Suppose your function has default arguments [1,2,3,4] and you supply [5,6]:
[1,2,3,4].concat([5,6]) produces [1,2,3,4,5,6].
Why not simply concatenate, and use the prototype? Arrays are passed by reference in javascript, so this will keep curried the same, while concatenating arguments to the call. Equivalently, you could write this:
curried2 = curried.concat(arguments);
return fn.apply(
(.....)
curried2);
Admittedly, the terseness does not help the understandability of this example. Simply re-naming arguments to calledArguments and curried (an advanced math term not relevant to the explanation) to be defaultArguments and using a simple for loop over each argument would be far easier to understand, if a little more verbose. I guess the author wanted to be fancy.
step 10: Why assign the "fn.prototype" as the prototype to "bound.prototype"?
Go up a bit on the article to the part where the author talks about the default bind function and how it works: basically, the end result of replacing the prototype back with the default prototype during the function call means that when your softbind enabled function is called with the new operator this will be set to itself, rather than the default bound object. prototype will not work when simply calling the bound function.
It also enables inheritance, meaning that creating things for a softbind enabled function using its prototype will not have that prototype be overruled by that of softbind when it is bound. (That would make softbind incompatible with prototypes). Instead, both prototypes are used.
Also see this reddit post.
A word of warning
We're extending the language with new features here. Features that aren't exactly necessary, and are largely concerned with semantics. If you're just interested in learning the language, this really goes way too far, you don't exactly need special binding semantics. Worse, it can be confusing if this does not behave in a way you expect it to.
A simpler alternative
Enable strict mode. Now this will default to undefined whenever it points to the global object. Prevents the problem this convoluted code is trying to solve (by usually resulting in errors from functions trying to access member variables or functions of undefined), while at the same time being far easier to use, and at the same time it will complain about a lot of syntax that is valid regular javascript, but a bug in any normal use-case. Also see the MDN article about it. It will catch a lot of potential errors for you instead of silently doing nonsensical things.
Another alternative
bind tries to resolve 'losing' the object when you pass a member function of it to another function, such as setTimeout. Another way of doing it is by using an anonymous function. Instead of using (soft) binding, assuming obj is an object holding a function fn being passed a parameter param;
setTimeout(obj.fn(param), 500);
You can use:
setTimeout(function(param){obj.fn(param);}, 500);
Which avoids the problem through a layer of indirection by passing an anonymous function. Also see this question.
According to this JavaScript reference:
The value null is a JavaScript literal representing null or an "empty"
value, i.e. no object value is present. It is one of JavaScript's
primitive values.
function getMax(arr){
return Math.max.apply(null, arr);
}
Wouldn't explicitly passing the keyword this be clearer, or at least more readable? Then again, at this point I may not understand why you would use null.
Why would you pass 'null' to 'apply' or 'call'?
When there is no value you wish to specify for the this pointer inside the function and the function you're calling is not expecting a particular this value in order to function properly.
Wouldn't explicitly passing the keyword this be clearer? Or at least
more human readable. Then again at this point I may not understand why
you would use null.
In your specific case, probably the best thing to pass is the Math object:
function getMax(arr){
return Math.max.apply(Math, arr);
}
While it turns out that it doesn't matter what you pass as the first argument for Math.max.apply(...) (only because of the implementation specifics of Math.max()), passing Math sets the this pointer to the exact same thing that it would be set to when calling it normally like Math.max(1,2,3) so that is the safest option since you are best simulating a normal call to Math.max().
Why would you pass 'null' to 'apply' or 'call'?
Here are some more details... When using .call() or .apply(), null can be passed when you have no specific value that you want to set the this pointer to and you know that the function you are calling is not expecting this to have any specific value (e.g. it does not use this in its implementation).
Note: Using null with .apply() or .call() is only usually done with functions that are methods for namespace reasons only, not for object-oriented reasons. In other words, the function max() is a method on the Math object only because of namespacing reasons, not because the Math object has instance data that the method .max() needs to access.
If you were doing it this way:
function foo() {
this.multiplier = 1;
}
foo.prototype.setMultiplier = function(val) {
this.multiplier = val;
}
foo.prototype.weightNumbers = function() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += (arguments[i] * this.multiplier);
}
return sum / arguments.length;
}
var x = new foo();
x.setMultiplier(3);
var numbers = [1, 2, 3]
console.log(x.weightNumbers.apply(x, numbers));
When the method you are calling .apply() on needs to access instance data, then you MUST pass the appropriate object as the first argument so that the method has the right this pointer to do its job as expected.
Calling apply with null as the first argument is like calling the function without providing any object for the this.
What does the apply method do?
The apply() method calls a function with a given this value and
arguments provided as an array (or an array-like object).
fun.apply(thisArg, [argsArray])
thisArg
The value of this provided for the call to fun. Note that this may not
be the actual value seen by the method: if the method is a function in
non-strict mode code, null and undefined will be replaced with the
global object, and primitive values will be boxed.
Further documentation can be found here.
One case where I have found this useful is when the function I'm calling is already bound to a particular context.
Because bound functions cannot be rebound, and they will always be called with the thisArg that was passed into bind, there is no use in passing a thisArg into call or apply. From source:
The bind() function creates a new bound function (BF).... When bound function is called, it calls internal method [[Call]] on [[BoundTargetFunction]], with following arguments Call(boundThis, args).
Here's an example:
class C {
constructor() {
this.a = 1;
}
}
function f(n, m) {
console.log(this.a + n + m);
}
let c = new C();
var boundF = f.bind(c, 2); // the context `c` is now bound to f
boundF.apply(null, [3]); // no reason to supply any context, since we know it's going to be `c`
I am bit late to answer this. I will try to give a long descriptive explanation here.
What is null in JavaScript?
The value null is a literal (not a property of the global object like undefined can be). It is one of JavaScript's primitive values.
In APIs, null is often retrieved in place where an object can be expected but no object is relevant.
fun.apply(thisArg, [argsArray])
thisArg: The value of this provided for the call to fun. Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode code, null and undefined will be replaced with the global object, and primitive values will be boxed.
argsArray: An array-like object, specifying the arguments with which fun should be called, or null or undefined if no arguments should be provided to the function. Starting with ECMAScript 5 these arguments can be a generic array-like object instead of an array. See below for browser compatibility information.
If you are using 'strict mode', then it is advisable to pass the this or
Math as the parameter.
Apply is useful when you want to pass along the responsibility for doing something to a function that is determined at run time, and pass a variable number of arguments to that function. You may or may not have any appropriate "this" context when you're doing that.
For example I use a library I wrote to facilitate listening for and raising application events that uses apply.
I wanted to be able to be able to raise an event like this:
EventManager.raise('some:event-name', arg1, arg2, arg3, ..);
..and have all of the registered handlers for that event get called with that list of arguments (arg1, arg2, etc). So in the raise function, it goes through the handlers that are registered for that event name and calls them, passing all the passed in arguments except for the event name, like this:
var args = [];
Array.prototype.push.apply(args, arguments);
args.shift();
for (var l in listeners) {
var listener = listeners[l];
listener.callback.apply(listener.context, args);
}
When a registered handler (listener.callback) is called, apply is used to pass along a variable number of arguments. Here I have allowed the listener to supply a this context for its event handler when the listener is defined, but that context might not be defined or it might be null, and that's perfectly fine.
For a long time the raise function didn't even facilitate using any callback context. I eventually came across a need for it, so I put in support for it, but most of the time I don't really need or use it.
Recently I started learning JavaScript through Nicholas C. Zakas' book Professional JavaScript For Web Developers and I came across some questions that I could not solve by myself.
As the title says, that's all about named arguments and arguments object in JavaScript functions.
E.g. we have this piece of code:
function doAdd(num1 , num2) {
arguments[1] = 10;
alert(arguments[0] + num2);
}
doAdd(10 , 20);
The book says that values in the arguments object are automatically reflected by the corresponding named arguments, so num2 enters the function with a value of 20 and then it gets overwritten via arguments[1] and finally gets a value of 10.All good all clear up to this point. Then it says that
this effect goes only one way: changing the named argument does not result in a change to the corresponding value in arguments.
And that's where the problems start.
I tried to modify this code a bit to understand what the author says but I failed.
E.g.
function doAdd(num1 , num2) {
arguments[1] = 10;
num2 = 40;
alert(arguments[0] + arguments[1]);
}
doAdd(10 , 20);
This time num2 enters function with a value of 20 again, it changes to 10 via arguments[1] and then it changes once more to 40 via the named argument num2 this time. Alert pops up 50, since a change to a named argument does not result in a change to the corresponding value in arguments. Why does alert not pop up 20?
This is because the book assumes you're using strict mode.
If you run the code in strict mode, you'll get the behavior you'd expect given what's written in the book.
function doAdd(num1 , num2) {
"use strict";
arguments[1] = 10;
num2 = 40;
alert(arguments[0] + arguments[1]);
}
doAdd(10 , 20); // this alerts 20, alerts 50 in nonstrict mode
A little known fact is that the entire point of strict mode is to avoid this sort of dynamic scoping (which is why arguments is fixated, with isn't allowed and eval behaves differently). Aside from clarity gains, this allows for massive speed improvements.
Also see this:
For strict mode functions, the values of the arguments object‘s properties are simply a copy of the arguments passed to the function and there is no dynamic linkage between the property values and the formal parameter values.
This is what NCZ means in context, quoting the book itself:
Strict mode makes several changes to how the arguments object can be used. First, assignment,
as in the previous example, no longer works. The value of num2 remains undefined even though
arguments[1] has been assigned to 10. Second, trying to overwrite the value of arguments is a
syntax error. (The code will not execute.) - Page 82, Language Basics, Professional JavaScript, Nicholas C. Zakas
Quoting from ECMA 5.1 Specifications for Arguments Object,
NOTE 1 For non-strict mode functions the array index (defined in 15.4) named data properties of an arguments object whose numeric name values are less than the number of formal parameters of the corresponding function object initially share their values with the corresponding argument bindings in the function’s execution context. This means that changing the property changes the corresponding value of the argument binding and vice-versa.
It didn't alert 20 because, as per the ECMA 5.1 specifications, in a non-strict mode function, mutating arguments object with the numeric key, will also change actual formal parameter corresponding to the numeric key.
In your case, when you change arguments[1], you are also changing the second parameter. The same way, when you change num2, you are also changing arguments[1].
I’d like to know both for regular all-in-the-family JS developer-defined functions, as well as predefined DOM methods: what happens if I try to call IE’s attachEvent with the signature of the WHATWG’s addEventListener? For instance:
elem.attachEvent('onbillgates\'mom', function(e){ this.mount(); }, false);
Specifically, note the third argument false. Will that trip anything up, even though the attachEvent method’s signature only calls for two arguments?
What about this example?
function foo(FirstOf2, SecondOf2) {
console.log(FirstOf2 + SecondOf2);
}
foo(1, 2, true);
JavaScript doesn't have the concept of a fixed parameter list. For your own functions you can always specify as many parameters as you want and pass in as many as you want which ever type you want.
For built-in functions, which correlate to native code, it depends.
You asked on what it depends:
Let's look at the ECMA-262
Section 15 about built-in (not to confuse with host) functions in general
Unless otherwise specified in the description of a particular function, if a function or constructor described in this clause is given fewer arguments than the function is specified to require, the function or constructor shall behave exactly as if it had been given sufficient additional arguments, each such argument being the undefined value.
Alright. If I pass in less arguments than needed, it depends on the spec of the function itself (scroll down section 15 to find the spec for each built-in function).
Unless otherwise specified in the description of a particular function, if a function or constructor described in this clause is given more arguments than the function is specified to allow, the extra arguments are evaluated by the call and then ignored by the function. However, an implementation may define implementation specific behaviour relating to such arguments as long as the behaviour is not the throwing of a TypeError exception that is predicated simply on the presence of an extra argument.
Passing in too many arguments should never raise a TypeError. But still it may raise other errors. Again, it depends on the function you talk about.
You were talking explicitly about the DOM and not about built-in functions. To be honest I can't find the corresponding parts of the spec. The ECMA spec is so much easier to read then the w3 website.
Won't hurt. You can even call a function with less parameters than it takes, as long as the function code is ok with a few undefined values.
I came across this important, however old, question; and I hope it'll be beneficial for future generations to share my experiments with it:
One can use the arguments object in order to access a function's arguments, regardless of the amount of arguments in the function's signature.
It's worth mentioning that this doesn't apply to arrow functions:
function singleArg(x) {
console.log(arguments);
}
singleArg(1, 2); // Called with 2 arguments
singleArg(); // Called with 0 arguments
// Results in an error, as 'arguments' isn't defined for arrow functions
((arg) => console.log(arguments))(1);
It's stated in the documentation that arguments isn't exactly an Array:
“Array-like” means that arguments has a length property and properties indexed from zero, but it doesn't have Array's built-in methods like forEach() and map().
Hence the following code results in an error:
(function singleArg(x) {
console.log(arguments); // This line works
arguments.forEach(x => console.log(x)); // This causes an error
})(1, 2);
Upon calling a function with less arguments than in its signature, they're assigned undefined:
(function twoArgs(a, b) {
console.log(`a: ${a}\nb: ${b}`);
})(1);
Try taking a look at this post and perhaps this one.
From MDN:
The arguments object is a local variable available within all
functions; arguments as a property of Function can no longer be used.
You can refer to a function's arguments within the function by using
the arguments object. This object contains an entry for each argument
passed to the function, the first entry's index starting at 0.
You can use the arguments object if you call a function with more
arguments than it is formally declared to accept. This technique is
useful for functions that can be passed a variable number of
arguments.
function myConcat(separator) {
var result = "";
// iterate through non-separator arguments
for (var i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}
I don't think it will mess anything up unless you are explicitly dealing with the implicit arguments array. Why are you doing this though?