Why can't I skip parameter assignments in a function signature? - javascript

With array destructuring, it's possible to discard leading items by inserting commas without a preceding reference:
const [ , two ] = [ 1, 2 ]
The same isn't true of function signatures — the following code won't parse because the leading comma in the signature is unexpected:
function ditchFirstArgument( , second ){}
Why do I need to provide references for leading parameters in ES6 function expressions?

Roman's insight from Go is useful but inappropriate to JS where the token _ is a valid reference, conventionally used by the Underscore and later Lodash libraries.
Even if that's acceptable, you'd have to create and avoid dud references for every unused argument, which isn't ideal.
However, it is possible to destructure a function argument into an empty object, which effectively nullifies the parameter without reference.
function take_third( {}, {}, third ){
return third
}
EDIT: As Paul points out in the comments, this will throw if any of the skipped parameter values are null or undefined. undefined values can be guarded against with default assignments, but this won't work for null:
function take_third( {} = {}, {} = {}, third ){
return third
}

Why do I need to provide references for leading parameters in ES6 function expressions?
Because otherwise it would be a syntax error. In not just ES6 but any version of the language you cannot elide formal parameters because the spec does not provide for it.
If you really want to do this (but why?), you could write it as
function ditchFirstArgument(...[, second]) {}
or at least you will be able to in some future version of ES; see https://github.com/tc39/ecma262/commit/d322357e6be95bc4bd3e03f5944a736aac55fa50. This already seems to be supported in Chrome. Meanwhile, the best you can do is
function ditchFirstArgument(...args) {
const [, second] = args;
But why does the spec not allow elision of parameters?
You'd have to ask the people who wrote it, but they may have never even considered it, or if they did, rejected it because it's bug-prone, hardly ever necessary, and can easily be worked around using dummy formal parameters like _.

I believe it's a common pattern to name unused variables with an underscore:
function ditchFirstArgument(_, second) { /* ... */ }
While it would not prevent you from actually using this variable (like in Go), it seems to be a pretty straightforward workaround.

Related

What are all the ways you can pass arguments into functions in JavaScript?

Coming from Python into some JavaScript-based APIs I'm confused by some of the syntax. And I can't find an answer in all of the noise of random information about declaring functions.
In Python, you can mix specifying arguments to a function base on the order and based on the name:
np.arange(1,5,step = 5)
Can you do something like that in Javascript?
If there is a function like:
ee.List.sequence(start,end, step, count)
and it only needs three out of the four arguments I can really easily specify the start, end, step, like so:
ee.List.sequence(1,100,2)
But, do I have to use the object notation to specify the count?
ee.List.sequence({start=1,end=100, count=50})
Is there a shorthand, like in Python, such as:
ee.List.sequence(1,100,{count=50})
or
ee.List.sequence(1,100,,50)?
It seems that what you are really asking is less about JavaScript as a language and more about specific APIs. So, here's some things to know:
In JavaScript, all arguments are optional. In other words, there is no way to enforce that a function is called with the proper amount or order of arguments. It's up to the caller to know the signature of the function its calling and call it appropriately. It's also up to the creator of the function to be prepared for some or all of the arguments to not be passed. There is an arguments array-like object that all functions have that can assist with this, but checking the inputs is also pretty easy. Here's an example:
// Here's an example of a function that does not explicitly declare any arguments
function foo1(){
// However, arguments might still be passed and they can be accessed
// through the arguments object:
console.log("Arguments.length = ", arguments.length);
console.log(arguments);
}
foo1("test", "boo!"); // Call the function and pass args even though it doesn't want any
// ***********************************************
// Here's an example of a function that needs the first arg to work,
// but the seond one is optional
function foo2(x, y){
if(y){
console.log(x + y);
} else {
console.log(x);
}
}
foo2(3);
foo2(4, 5);
In JavaScript, your functions can take any valid primitive or object. Again, it's up to the caller to know what the API is and call it correctly:
function foo1(string1, number1, object1, string2){
console.log(arguments);
}
foo1("test", 3.14, {val:"John Doe"}, "ing");
I've found the answer in this JavaScript tutorial.
In general, yes, the default JavaScript function can take anything as an argument. But any well-written API function, with specified arguments (and default values), will not allow this to happen.
So the two options are
Supply the arguments in order, without naming them.
`ee.List.sequence(1,100,2)`
Pass them in a named object (where suddenly order doesn't matter)
`ee.List.sequence({start=1,end=100, count=50})`
There is no mixed notation like Python has
ee.List.sequence(1,100,{count=50})
BUT there is a workaround for 1
In case you want to use a different combination of arguments, one can supply null values to the arguments that are omitted. So the following can be used:
`ee.List.sequence(1,100,null,50)`

Why AMD defines its optional arguments in a reverse order of javascript's nature?

As far as I know, a lot of javascript code still use IIFE as a pattern of their namespace, and I believe javascript developers are accustomed to there are usually something afters, don't expect you would see everything if you read the code just from the beginning; sometimes empty parenthesis, sometimes more arguments.
I read into part of require.js, and saw the additional arguments adjustment in its define implementation:
define=function (name, deps, callback) {
var node, context;
//Allow for anonymous modules
if (typeof name!=='string') {
//Adjust args appropriately
callback=deps;
deps=name;
name=null;
}
//This module may not have dependencies
if (!isArray(deps)) {
callback=deps;
deps=null;
}
// ..
I'd like to understand things better of why it is defined in this way, and should I follow this fashion when I'm going to define my own APIs?
The spec: AMD
Functions that accept arguments in a random or very optional order just give you some syntactic sugar. It's not necessarily something you should aim for but it's nice if it works out.
I can give an example where the arguments are not nice:
JSON.stringify(data_obj, undefined, "\t");
You have to pass undefined as the replacer function (because I don't have a replacer function, it's optional). Of course it would be trivial to add something like the code you posted that checks the type of the 2nd and 3rd argument to reduce it to:
JSON.stringify(data_obj, "\t");
In Java (not JavaScript) you have polymorphic functions like:
public function get(String string, List list) {}
public function get(List list) {}
Depending on how you call get it will call either of those implementations. When you implement these you might see something like:
public function get(String string, List list) {
/* actual implementation */
}
public function get(List list) {
this->get("", list); // call get with default 1st argument
}
So there isn't really that much substance to it, just syntactic sugar.

Is it a good idea to use a switch with fallthrough to handle default arguments in Javascript?

I have recently learned that you can use a neat switch statement with fallthrough to set default argument values in Javascript:
function myFunc(arg1, arg2, arg3) {
//replace unpassed arguments with their defaults:
switch (arguments.length) {
case 0 : arg1 = "default1";
case 1 : arg2 = "default2";
case 2 : arg3 = "default3";
}
}
I have grown to like it a lot, since not only is it very short but it also works based on parameters actually passed, without relying on having a special class of values (null, falsy, etc) serve as placeholders as in the more traditional versions:
function myFunc(arg1, arg2, arg3){
//replace falsy arguments with their defaults:
arg1 = arg1 || "default1";
arg2 = arg2 || "default2";
arg3 = arg3 || "default3";
}
My inital though after seeing the version using the switch was that I should consider using it "by default" over the || version.
The switch fallthough makes it not much longer and it has the advantage that it is much more "robust" in that it does not care about the types of the parameters. In the general case, it sounds like a good idea to not have to worry about what would happen with all the falsy values ('', 0, null, false ...) whenever I have to make a function with default parameters.
I would then reserve the arg = arg || x for the actual cases where I want to check for truthyness instead of repurposing it as the general rule for parameter defaulting.
However, I found very few examples of this pattern when I did a code search for it so I had to put on my skeptic hat. Why didn't I find more examples of this idiom?
Is it just now very well known?
Did I not search well enough? Did I get confused by the large number of false positives?
Is there something that makes it inferior to the alternatives?
Some reasons that I (and some of the comments) could think of for avoiding switch(arguments.length):
Using named parameters passed via an object literal is very flexible and extensible. Perhaps places where more arguments can be optional are using this instead?
Perhaps most of the time we do want to check for truthyness? Using a category of values as palceholders also allows default parameters to appear in the middle instead of only at the end : myFunc('arg1', null, 'arg3')
Perhaps most people just prefer the very short arg = arg || "default" and most of the time we just don't care about falsy values?
Perhaps accessing arguements is evil/unperformant?
Perhaps this kind of switch case fallthrough has a bad part I didn't think about?
Are these cons enough to avoid using switch(arguments.length) as a staple default argument pattern or is it a neat trick I should keep and use in my code?
Since the question has been updated, it's really a matter of opinion. There are a number of javascript features that many people suggest avoiding, such as switch and ternary. This is why there is not a lot of information on some of those features.
The reason that suggestion is made is because many people miss-use those features and create problems in their code. The bugs are sometimes difficult to detect and it can be difficult for others to understand what your code is doing (particularly those unfamiliar with javascript or new programmers).
So if you like to do it that way, and you're not worried about the opinions (or skill level) of anyone working on your code. By all means, your approach will work. I have used the switch statement myself on occasion, and while I don't think it's really "good" or "bad", it's hard to find a situation that requires it.
You asked how I might go about this without an if-else chain:
function myFunc(args) {
var allArgs = {
arg1:"default1",
arg2:"default2",
arg3:"default3"
};
for (var key in args) {
allArgs[key] = args[key];
}
}
myFunc({arg1:null, arg3:'test'})
Just a guess, but Doug Crockford discourages the use of switch statements in 'JavaScript: the Good Parts.' His logic is that switch statements are a common source of bugs because it's difficult to locate them when using 'fall through' logic. It's easy to see when a case is triggered, but it's often difficult to determine if every case in a result set has been covered, especially if it's not your code.

Argument question javascript

One more question regarding arguments in javascript. I was reading a tutorial about the javascript framework Prototype and came over the following text, I will quote below:
"If you have some DOM methods of your own that you'd like to add to those of Prototype, no problem! Prototype provides a mechanism for this, too. Suppose you have a bunch of functions encapsulated in an object, just pass the object over to Element.addMethods():
var MyUtils = {
truncate: function(element, length){
element = $(element);
return element.update(element.innerHTML.truncate(length));
},
updateAndMark: function(element, html){
return $(element).update(html).addClassName('updated');
}
}
Element.addMethods(MyUtils);
// now you can:
$('explanation').truncate(100);
The only thing to watch out here is to make sure the first argument of these methods is the element itself. In your methods, you can also return the element in the end to allow for chainability (or, as practiced in the example, any method which itself returns the element)."
Everything seems pretty straightforward except one thing that I seem to have problem understanding. It says that you need to make sure the first argument of these methods is the element itself. And that is the case in the functions but when you call the function you only provide 1 argument? So for example:
$('explanation').truncate(100);
There is only 1 argument here that is sent to the function namely 100, but the function signature looks like this:
truncate: function(element, length){
So element comes from where? And is it logic that you must make sure that the first argument is the element itself but you do not provide it when you call the function?
Prototype provides two ways to do things:
Methods on the object itself, for example:
Element.toggleClassName('selector', 'something');
Via the prototype:
$('selector').toggleClassName('something');
IIRC, the second method simply calls the first, passing the Element selected to it as well as the original argument. That's what happens in your case as well.
Javascript functions can test their arguments and decide what to do based on what was passed. jQuery is famous for this and it's fairly common in a lot of libraries. It allows one named function to perform many different (but related) operations and often allows shorthand notation that can omit optional or default parameters. You can often pass one, two or three arguments and the code inside the function will examine which arguments are present and, in some cases, the type of the arguments to decide how to treat them.
When functions do this, you have to read their documentation carefully to see which parameters are required and which are optional and what order things can be passed in.
If a function optionally takes three parameters and all three are different types, it's possible for the function to examine the type of each passed parameter and accept them in any order. It can tell which is which by the type. I don't personally think this is good programming style, but it is possible. More likely, it allows you to just leave out some parameters which are not needed and the function will either adapt it's behavior when some things are missing or will set a default for that value.
In your specific example of truncate, I'd have to see a documentation page for that function to explain what it does when no element is passed vs. when one is.
Here's a made up example of a string truncate function that can be used a bunch of different ways:
var str = "This is a long string that I want to be truncated to something shorter";
str.truncate(10); // truncate to max length of 10
str.truncate("string", "end"); // truncate after the first occurrence of "string"
str.truncate(/\bbe\b/, "begin"); // truncate before the first occurrence of a regular expression
str.truncate("string", 10); // truncate 10 chars after the first occurrence of "string"
And the outline of this function would look something like this:
string.prototype.truncate = function(lookFor, pos, cnt) {
if (lookFor == undefined) {
return(this); // no parameters passed, nothing to do
}
if (typeof lookFor == "Number") {
// truncate to a certain length
} else if (typeof lookFor == "String") {
// look for a plain string
} else if (lookFor.exec) {
// look for a regular expression
} else {
return(this); // nothing to do
}
}

Javascript - Passing arguments to function

I've always passed arguments to a function like so:
setValue('foo','#bar')
function setValue(val,ele){
$(ele).val(val);
};
Forgive the silly example. But recently I have been working on a project that has some functions that take a lot of arguments. So I started passing the arguments through as an object (not sure if that's the correct way to put that), like so:
setValue({
val:'foo',
ele:'#bar'
});
And then in the function:
function setValue(options){
var value = options.val;
var element = options.ele;
$(element).val(value);
};
My question is, is there a better way to do that? Is it common practice (or okay) to call these 'options'? And do you typically need to 'unpack' (for lack of a better term) the options and set local vars inside the function? I have been doing it this way in case one of them was not defined.
I'm really looking to not create bad habits and write a bunch of code that is ugly. Any help is appreciated and + by me. Thanks.
I do the exact same thing, except I don't declare a new variable for each option inside the function.
I think options is a good name for it although I shorten it to opts.
I always have a "default" object within the function that specify default values for each available option, even if its simply null. I use jQuery, so I can just use $.extend to merge the defaults and user-specified options like this: var opts = $.extend({}, defaults, opts);
I believe this is a great pattern. I've heard an options object like this referred to as a "builder object" in other languages (at least in the context of object creation). Here are some of the advantages:
Users of your function don't have to worry about what order the parameters are in. This is especially helpful in cases like yours where the method takes a lot of arguments. It's easy to get those mixed up, and JavaScript will not complain!
It's easy to make certain parameters optional (this comes in handy when writing a plugin or utility).
There are some pitfalls though. Specifically, the user of your function could not specify some of the options and your code would choke (note that this could also happen with a normal JS function: the user still doesn't have to supply the correct arguments). A good way for handling this is to provide default values for parameters that are not required:
var value = options.val || 0;
var element = options.ele || {};
$(element).val(value);
You could also return from the function immediately or throw an exception if the correct arguments aren't supplied.
A good resource for learning how to handle builder objects is to check out the source of things like jQueryUI.
I realize this question is a year old, but I think the cleanest way to pass an arbitrary number of arguments to a JavaScript function is using an array and the built in apply method:
fun.apply(object, [argsArray])
Where fun is the function, object is your scope/context in which you want the function to be executed and the argsArray is an array of the arguments (which can hold any number of arguments to be passed.
The current pitfall right now is that the arguments must be an array (literal or object) and not an array-like object such as {'arg' : 6, 'arg2' : "stuff"}. ECMAScript 5 will let you pass array-like objects, but it only seems to work in FireFox at the moment and not IE9 or Chrome.
If you look at the jQuery implementation, it uses an options class to handle most of the arbitrary-number-of-parameters functions, so I think you are in good company.
The other way is to test for arguments.length, but that only works if your arguments are always in the same order of optionality.
It's worth remembering that all functions have a bonus parameter called arguments that is an object very much like a JS array (it has length but none of the array functions) that contains all the parameters passed in.
Useful if you want to pass in a range of parameters (e.g.
function Sum() {
var i, sum = 0;
for (i=0; i < arguments.length; i++){
sum+=arguments[i];
}
return sum;
};
If this isn't the case and you just have a lot of parameters, use the params object as you've described.
Nothing wrong with that practice.
"Options" seems like as good a name as any.
You don't need to "unpack" them, but if you'll be accessing the same item several times, it will be a little more efficient to reference them in local variables because local variable access is generally quicker than property lookups.

Categories