A colleague advised me to add "use strict"; to the top of my JS code to highlight any gaps in my definitions and potential reference errors, etc. I am very happy with it because it has identified several pieces of code which might have been a problem down the line.
However, another colleague advised me that when calling functions which take multiple arguments, it can be helpful to name the arguments as they are specified, especially if it's something like a bunch of booleans. To illustrate, here's a couple of function calls:
logData(data, target, preserveLog=true, changeClass=false, wrapLine=false);
...is a whole lot clearer than:
logData(data, target, true, false, false);
But "use strict"; hates this. everywhere I've done this, I get a reference error in the console. It still runs fine, as would be expected, but the console is now cluttered with all these apparently non-defined references.
Does anyone know if there's a way around this so that I can keep my coding conventions which my colleagues appreciate, or am I going to have to either stop using "use strict"; or go through all my code and remove the names of arguments?
Thanks.
However, another colleague advised me that when calling functions which take multiple arguments, it can be helpful to name the arguments as they are specified, especially if it's something like a bunch of booleans.
This is terrible advice!
Javascript doesn't actually support passing arguments by name this way. Each of the arguments you pass "by name" is actually being treated as an assignment to a global variable with that name, and "use strict" is correctly identifying this as an error.
If you want to be more clear about what values you're passing, assign the values to real local variables and pass those, e.g.
var preserveLog = true;
var changeClass = false;
var wrapLine = false;
logData(data, target, preserveLog, changeClass, wrapLine);
If you really wanted to keep using your original pattern, you could even assign to those variables in the function call, so long as you declare them as local variables first:
var preserveLog, changeClass, wrapLine;
logData(data, target, preserveLog=true, changeClass=false, wrapLine=false);
(With a hat-tip to dav_i for this answer, which I based my recommendation off of.)
Duskwuff has already provided an excellent answer and I won't add anything to that, other than to say I fully agree with it, but he didn't mention any conventions that arose due to ES6.
In ES6, you still don't have named parameters, but you have the next best thing, which is Object destructuring assignment.
This allows us to pass what appears to be named parameters, but are really just destructured object properties of an object that is never directly used.
In the context of the example you provided, it would look something like this:
logData({data, target, preserveLog:true, changeClass:false, wrapLine:false});
Where the function is defined as:
function logData({data, target, preserveLog, changeClass, wrapLine}) { ... }
I've seen a lot of libraries that prefer this calling convention where ES6 is available, and it's very convenient too because the order of the parameters is also no longer important.
Related
To which extent does it make sense to pass plenty of global values to an IIFE?
The common thing is just to pass 3 as far as I see everywhere (window, document and undefined).
But... would it make sense to pass more if they are used more than 10 times in the code just for the fact of minification?
In my case I found the global variable Math 14 times in the code. It would make sense to pass it to an IIFE in order to save 42 bytes. Which in this case is not a lot, but if we sum bit by bit different global variables, then it would always make sense to pass as many global variables as possible, right? (Symbol, Object, Error, Date, JSON...)
(function($, window, document, Math, undefined) {
$.fn.mydemo = function() {
};
}(jQuery, window, document, Math));
Then, why isn't this a common approach?
Update:
To explain the 42 bytes of reduction:
Math = 4 characteres
1 character = 1 byte
14 times Math = 56 bytes
Math will get replaced by a single character after minification
As the function can be defined as function($, w, d, m, u)
14 characters of the shorten word Math (m) = 14 bytes
56 - 14 = 42 bytes of reduction
First of all, those values are not IIFEs.
And this is not about “saving characters” by having shorter variables names inside the function (at least not mainly), but rather about variable lookup and the “cost” associated with it.
If you were to use f.e. document inside your function without passing it in, then first a variable named document would be searched in the scope of the function, and only when that fails, search would continue in the scope above that, and so on.
That is the reason for passing such objects as parameters into the function – so that a direct reference to them within the function scope exists, and they do not have to be looked up in higher outside scopes.
Sometimes, you might even see this used in such a form like this:
(function(document) {
// do something with document, such as:
document.foo();
document.bar = "baz";
})(document);
– in that form, it should be even more clear that this is not about saving characters in variable names. The object is still referred to as document inside the function (which makes it clear what it is supposed to represent – the global document object), and the only effect achieved by this is said shorter lookup.
There are a number of cases where it makes sense to pass variables to an IIFE.
Aliasing
Passing a variable to an IIFE allows you to rename the variable within the function. This is commonly seen when using jQuery, particularly when noConflict is used:
(function ($) {
//in here $ will be the same as jQuery
}(jQuery));
Aliasing also helps minifiers to minify code, when you see something like:
(function (document, slice, Math) {
...
}(document, Array.prototype.slice, Math));
The minifier can rename the parameters to whatever it wants, and save you bytes. For large scripts using these properties a lot, it can be significant savings when it gets turned into:
(function(a,b,c){...}(document,Array.prototype.slice,Math));
Portability
This is more of an edge case than a general rule, but it's common to see a global IIF in the form of:
(function (global /* or window */) {
...
}(this));
This allows for portability between node.js and the browser so that the global variable has the same name in both environments.
Character Savings
While I already mentioned that minifiers can reduce the character count by changing the names of aliases, you may want to do this manually if you're participating in a code golf challenge.
Reference Safety
If you're authoring a script that must work in whatever environment its dumped into (think google analytics), you'll want to be sure that the global methods you're calling are what you expect. Storing a reference to those functions by passing them as parameters is one way to preserve the reference to the functions from becoming overridden by a malicious or ignorant programmer.
To answer the question in your title:
How many globals make sense to be passed to the IIFE wrapper?
As many as you need and no more. If you need to alias one or two variables, pass one or two references. If you need to be sure that the global functions aren't being changed, you may end up with 100 parameters. There's no hard-and-fast rule on this.
would it make sense to pass more if they are used more than 10 times in the code just for the fact of minification?
If you care that much about minification, sure, why not?
The common thing is just to pass 3 as far as I see everywhere (window, document and undefined)
Yes, altough you see not passing document, or passing jQuery (aliased as $), just as often. And of course it's not only about minification, but about performance, and you only care for window and document on that behalf.
it would always make sense to pass as many global variables as possible, right?
Well, except you don't use them in your code. Symbol, Object, Error, Date, JSON, Math and the others are not needed that often in most code. And developers don't like to do those byte counts you are suggesting every time they change a bit of code, so this IEFE boilerplate just stays as it is (and imho there's much cargo cult to it).
You would let your minifier do this automatically if you'd really care.
I'm looking at Addy Osmani's gist for a publication/subscription pattern here:
https://github.com/addyosmani/pubsubz/blob/master/pubsubz.js
He surfaces his object as a global like this:
;(function ( window, doc, undef ) {
var topics = {},
subUid = -1,
pubsubz ={};
....
getPubSubz = function(){
return pubsubz;
};
window.pubsubz = getPubSubz();
What is the value of creating that getPubSubz function? Wouldn't it be more straightforward to simply write:
window.pubsubz = pubsubz;
Yes, in this case, because getPubSubz is only called in one place, immediately after declaring it, it could safely be inlined.
It's hard to say exactly what the author had in mind, but in a growing code base there may be some value to having a "getter" function which could be modified if the act of getting the pubsubz object required more advanced logic.
It absolutely would be.
There are only two potential reasons why a getter would be used in this case:
There was previously some additional code inside the getter (logging, perhaps)
Addy Osmani's just following good practice*, and including a getter—even adding the opportunity to add additonal code in the future.
Through the power of GitHub, we can actually eliminate option one, as the getter was added in its current state—so I think we can conclusively say that it's just a matter of good practice here.
*as jantimon alludes to in the comments below, this isn't particularly advantageous in most cases (including this one) and this code does not necessarily need to followed as an example.
Edit: I found this interesting library which looks like it can do exactly what I was describing at the bottom: https://github.com/philbooth/check-types.js
Looks like you can do it by calling check.quacksLike.
I'm fairly new to using javascript and I'm loving the amount of power it offers, but sometimes it is too flexible for my sanity to handle. I would like an easy way to enforce that some argument honors a specific interface.
Here's a simple example method that highlights my problem:
var execute = function(args)
{
executor.execute(args);
}
Let's say that the executor expects args to have a property called cmd. If it is not defined, an error might be caught at another level when the program tries to reference cmd but it is undefined. Such an error would be more annoying to debug than explicitly enforcing cmd's existence in this method. The executor might even expect that args has a function called getExecutionContext() which gets passed around a bit. I could imagine much more complex scenarios where debugging would quickly become a nightmare of tracing through function calls to see where an argument was first passed in.
Neither do I want to do something on the lines of:
var execute = function(args)
{
if(args.cmd === undefined || args.getExecutionContext === undefined ||
typeof args.getExecutionContext !== 'function')
throw new Error("args not setup correctly");
executor.execute(args);
}
This would entail a significant amount of maintenance for every function that has arguments, especially for complex arguments. I would much rather be able to specify an interface and somehow enforce a contract that tells javascript that I expect input matching this interface.
Maybe something like:
var baseCommand =
{
cmd: '',
getExecutionContext: function(){}
};
var execute = function(args)
{
enforce(args, baseCommand); //throws an error if args does not honor
//baseCommand's properties
executor.execute(args);
}
I could then reuse these interfaces amongst my different functions and define objects that extend them to be passed into my functions without worrying about misspelling property names or passing in the wrong argument. Any ideas on how to implement this, or where I could utilize an existing implementation?
I don't see any other way to enforce this. It's one of the side effects of the dynamic nature of JavaScript. It's essentially a free-for-all, and with that freedom comes responsibility :-)
If you're in need of type checking you could have a look at typescript (it's not JavaScript) or google's closure compiler (javascript with comments).
Closure compiler uses comments to figure out what type is expected when you compile it. Looks like a lot of trouble but can be helpful in big projects.
There are other benefits that come with closure compiler as you will be forced to produce comments that are used in an IDE like netbeans, it minifies your code, removes unused code and flattens namespaces. So code organized in namespaces like myApp.myModule.myObject.myFunction will be flattened to minimize object look up.
Cons are that you need to use externs when you use libraries that are not compiler compatible like jQuery.
The way that this kind of thing is typically dealt with in javascript is to use defaults. Most of the time you simply want to provide a guarentee that certain members exist to prevent things like reference errors, but I think that you could use the principal to get what you want.
By using something like jQuery's extend method, we can guarentee that a parameter implements a set of defined defaults.
var defaults = {
prop1: 'exists',
prop2: function() { return 'foo'; }
};
function someCall(args) {
var options = $.extend({}, defaults, args);
// Do work with options... It is now guarentee'd to have members prop1 and prop2, defined by the caller if they exist, using defaults if not.
}
If you really want to throw errors at run time if a specific member wasn't provided, you could perhaps define a function that throws an error, and include it in your defaults. Thus, if a member was provided by the caller, it would overwrite the default, but if it was missed, it could either take on some default functionality or throw an error as you wish.
I often find that I write IF statements which immediately reference the value of the conditional statement. For example, let's say I need to check to see if a string matches a pattern:
if (mystring.match(/mypattern/) {
var mymatch = mystring.match(/mypattern/)[1];
...
};
I suspect that what I'm looking for doesn't exist, but I've wondered whether you can reference the conditional statement's value within the if block, the way you can reference "arguments" within a function. In many cases, of course, I can rewrite it like this:
var mymatch = mystring.match(/mypattern/)[1];
if (mymatch) { ... };
But that's often not possible if there's a series of methods called. For example:
var mymatch = $('.myclass')[0].text().match(/mypattern/)[1];
... that would throw an exception if there were no item [0] on which to call .text(). Is there some convenient shorthand I'm missing out on? Or a better way to organize things? Just curious, really — I'll go on living if the answer is no.
In cases where relevant you can use the fact that the assignment operator returns a value in JavaScript, so for instance you can write things like:
if (assignedTest = testedValue) {
//value of assignedTest is now available
//and conditional will only be executed if true
This could be used if the RHS was compatible or properly set-up but it's also a huge readability concern since it's very easy to confuse the assignment = with comparison ==/===.
If you were particularly motivated to pursue this you could extract this type of functionality into a function that would behave in a reliable way: such as assigning the result of a closure to a named variable, and you could further tune the behavior to do other things (such as optionally evaluating to a different value within the test). Ultimately it would primarily be making a simple structure more complex though.
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.