I know very well that null and undefined are distinct in JavaScript. However, I can't seem to decide whether or not use that fact when my own functions are passed one of those as its argument.
Or, expressed in a different way, should myFoo(undefined) return the same thing as myFoo(null)?
Or, in yet another case, since myBar(1, 2, 3) is (almost) the same thing as myBar(1, 2, 3, undefined, undefined), should myBar(1, 2, 3, null, null) return the same thing as myBar(1, 2, 3)?
I feel that there's potential for confusion in both cases and that a library should probably follow a convention when handling null/undefined.
I'm not really asking for personal opinions (so please express those as comments rather than answers). I'm asking if anyone knows if there is a best practice that one should stick to when it comes to handling this distinction. References to external sources are very welcome!
I'd say that while, most of the time, there is little value in distinguishing between the two, the cases where there is value tend to be quite interesting.
Take, for example, a function which can be given a callback. undefined might indicate that some default callback should be used (as if the parameter weren't specified), but null could indicate that no callback should be made at all:
function asyncWorker(data, callback, timeout) {
if (typeof callback === "undefined") {
callback = function() { $("#log").append("<p>Done!</p>"); };
}
// ...
if (callback) callback();
}
asyncWorker([1, 2, 3]); // default callback, no timeout
asyncWorker([4, 5, 6], null); // no callback, no timeout
asyncWorker([7, 8, 9], undefined, 10000); // default callback, 10s timeout
Of course, false or 0 could be used instead of null here, but that might not be the case in a more complex example. And whether your code benefits from the additional parameter complexity is entirely up to you. :-)
Best practice for handling arguments
define the expected arguments, what they will be used for, and the types of these
decide how they are accessed, either via the formal arguments, or through the arguments collection
define whether values outside the expected range should result in default values
verify that the arguments are within range before processing
for boolean values, decide whether they must be true booleans, or only truthy/falsy
Step 2, 3 and 4 is of most importance to you in this case
How to access the arguments
This is something you will need to select based on what the method does, and your strategy for handling a variable amount of arguments.
Take this for example
function foo() {
var args = arguments.length == 1 ?
[document.body].concat([arguments[0]]) :
Array.prototype.slice.call(arguments);
args[0].style.backgroundColor = args[1];
}
foo(document.body, "red");
foo("blue");
True boolean or truthy/falsy
How to test for values depends largely on how your code is set up
function foo(elem, color) {
if (!color) { // the correct test here should be 'typeof color == "undefined"'
color = "green";
}
elem.style.backgroundColor = color;
}
foo(document.body, "red"); //set the background color to red
foo(document.body); //set the background color to the default green
foo(document.body, ""); //remove the background color !This will fail!
The last statement will wrongly use the default value instead of the provided, even though the provided is within the expected range.
When it comes to handling undefined values remember that there is no difference in foo(undefined); and foo(); except that the length of the arguments collection will be different. How this is handled (and if it needs to be) is dependent on how you access the arguments.
Its entirely up to you how you handle arguments passed to your function, so its up to you.
If you want to check if an argument is null you use
if (myVar === null) {
and if you want to check if an argument is undefined you use
if (typeof myVar === "undefined") {
If the expected argument is anything other than 0, null or undefined, then you can check for this using
if (myVar) {
So whether or not your myFoo(null) should behave the same as myFoo(undefined) is entirely up to how you handle these internally.
When it comes to extra parameters, this has no effect other than the arguments collection being larger than expected.
Related
I am relatively new to Javascript and am working through ch. 5 of Eloquent Javascript. I came across some code that I don't quite understand. I know HOW it works (the general method and steps), but I don't understand WHY it works.
The code is here:
function filter(array, test) {
var passed = [];
for (var i = 0; i < array.length; i++) {
if (test(array[i]))
passed.push(array[i]);
}
return passed;
}
Basically the function takes the element the 'for loop is iterating over' from the array, and compares it to the test parameter.
I am wondering how/why this works:
if (test(array[i]))
There is no || && or other 'comparison operators'. How does it compare values with only using parenthesis?
How is test compared to the array[i] value with no operators?
Link to file: http://eloquentjavascript.net/05_higher_order.html
go to 'Filtering an Array' exercise
Thanks!
Whatever is inside the parentheses of an if statement will be evaluated. If the result is falsy (false, 0, "", NaN, null, undefined) it fails and if the result is truthy (everything else) it passes. So if your if statement contains a function call if (test(something)) {}, then the if statement just says if the result of the function call is truthy then pass.
Also, && and || are not comparison operators, they are boolean operators. They just connect the result of two statements, like true || false which evaluates to true.
I am not quite sure, but I think this is a custom function. Most likely there is some comparison there and the result of the function is True/False. If you give us the whole code we could explain it better to you.
This code is accepting a test parameter that is what is called a "predicate function" i.e. a function that given an element will return true or false.
It's going to be used for example with
var big_numbers = filter(numbers, function(x){ return x > 100; });
i.e. the expected parameter test is actually code.
In Javascript passing code is very common and idiomatic. It's something that is more annoying in other languages that don't support the concept of "closure" and of "nested function", forcing all code to live at the top level, being given a name and to have no context (e.g. the C language).
'test' here is a function, not a value. In Javascript, each function is an object and can be passed as parameter. In this case, test is a function that take one parameter and return true or false base on the parameter value.
So in the for loop, test function is called with each array element and if the result is true, it will be store in another array. Eventually, passed elements would be return to the function caller.
I'm trying to refresh some Javascript knowledge for an upcoming interview. I was reading a blog that says
"The delete operator returns true if the delete was successful."
and then shows an example of it in use:
var christmasList = {mike:"Book", jason:"sweater" }
delete christmasList.mike; // deletes the mike property
In that example it looks like delete is used in the manner that a void function (in the general programming sense -- I know that JS doesn't require declarations like void) would be.
Can someone explain to me, or give me a link to, the documentation that explains how JS functions can act with different return values, and does such require separate implementations for each return value?
You can check the Delete operator which says:
If desc.[[Configurable]] is true, then
Remove the own property with name P from O.
Return true.
Note that delete only works for properties of objects. Also a good read:- JavaScript Delete() Only Affects The Referenced Object Regardless Of Prototype Chain
In that example it looks like delete is used in the manner that a void function
The delete operator is not a function, it is an operator. It deals with properties of objects, not their values.
Functions are something else, but since you asked:
Can someone explain to me how JS functions can act with different return values
JavaScript is loosely typed. Functions don't care about the types of values unless they need to, and (most of the time) conversion between types is handled by operators.
If a function needs to are about what it is operating on, then it has to examine the value to see what it is.
For example:
function myFunction(myArgument) {
if (typeof myArgument === "function") {
return myArgument();
} else {
return myArgument;
}
}
A function can return any value it likes.
function string_or_number() {
if (Math.random() > 0.5) {
return 1;
} else {
return "1";
}
}
Strongly typed languages care about what type of value a function returns and what type of value is passed into an argument.
Loosely typed ones simply don't. There's nothing special about it from the point of view of someone using the language.
It shunts most of the complexity about having to care about types to the compiler author instead of the user of the compiler (who just has to care that, if a function is designed to do something to a duck, what they pass is sufficiently like a duck to not break the function).
As others note, delete is technically an operator and not a function; for our immediate concerns, however, the difference is academic, as the operator's behavior is the same as that of many functions used for their side effects (which is to say, void functions). Both the rule of the language and the conventions of their use are simple.
Rule
All functions provide a return value; if no return statement is reached, this will be undefined
Conventions
Since we always get a return value, we can take advantage of it to improve our programs. There are two conventions; which one should be used depends on the use case.
Return a boolean, signalling success or failure
Return some object being operated on
Option 2 is most useful for methods on objects: if our method changes the state of the object and then returns the object, we can bundle several changes into a single line of method calls: object.change1().change2().change3(newVal);
Option 1 is most useful when we want to use the success or failure of an operation to determine program flow; maybe we want to throw an exception if the property was not deleted but continue normally if it was. Then we can use if (delete object.property) to attempt to delete the property and branch into success/failure cases immediately.
From the MDN on the delete operator:
Throws in strict mode if the property is an own non-configurable property (returns false in non-strict). Returns true in all other cases.
I can't make it simpler than that. Aside from a small example:
alert(delete window.window)
alert(delete window.foobar)
alert(delete window.alert)
Javascript functions always return ambigious values. One function can return boolean, string, object, array or HTMLElement.
There is no fixed type.
function masterSwitch(input) {
switch(input) {
case 0 : return "Hello";
case 1 : return 0xdead;
case 2 : return 0.00042;
case 3 : return document.createElement("DIV");
case 4 : return true;
case 5 : return window;
case 6 : return this;
case 7 : return null;
default:window.alert("Please specify input from 0 to 8");
}
}
<input type="text" id="output"> <SELECT onchange="document.getElementById('output').value = typeof masterSwitch(this.selectedIndex);">
<option>string</option>
<option>int</option>
<option>float</option>
<option>HTMLElement</option>
<option>boolean</option>
<option>window</option>
<option>this</option>
<option>null</option>
</select>
Check this fiddle or the code below:
function abc(s) {
console.log('in abc(s)');
}
function abc(s, t) {
console.log('in abc(s,t)');
}
abc('1');
The output of this question is always in abc(s,t)
Can someone please explain me whats going on here and why ?
In Javascript there is no overload concept.
You can however write a function that checks how many arguments have been passed by using the arguments value.
function foo(s, t) {
if (arguments.length == 2) {
...
} else {
...
}
}
all arguments that the function expects in the signature but that are not passed by the caller are received as undefined. You can also write variadic functions by simply accessing the n-th argument passed with arguments[i]. Note however that arguments is not a Javascript array, so not all array methods are available for it.
About being able to redefine the same function multiple times without errors things are a bit complex to explain because the rules are strange.
A simple explanation is you could think of is that function is an executable statement like it is in Python and so the last function definition wins. This would be wrong however because, differently from Python, the following is legal Javascript code:
console.log(square(12));
function square(x) { return x*x; }
i.e. you can call a function in lines that are preceding the definition (in a script: of course typing those two lines in a Javascript console wouldn't work).
A slightly more correct explanation is that the compiler first parses all the function definitions (last wins) and then starts executing the code. This mental model works if you don't put functions inside if because what happens in practice in that case is implementation dependent (and I'm not talking about crazy IE, but even that FF and Chrome will do different things). Just don't do that.
You can even use the form
var square = function(x) { return x*x; }
and in this case it's a simple assignment of a "function expression" to a variable that is executed when the flow passed through it (so it's ok to place different implementations of a function inside different if branches, but you cannot call the function before assigning it an implementation).
First, no method overload support in JavaScript (see #6502 workaround).
Second, to describe what you're experiencing, in JavaScript, the last declared function (with the same name) is invoked because the former has been overwritten, It relates to JavaScript Hoisting.
Try to reorder the functions declarations and see the output result again:
function abc(s, t) {
console.log('in abc(s,t)');
}
function abc(s) {
console.log('in abc(s)');
}
abc('1');
In javascript, there is only one function with any given name and if multiple functions with the same name are declared, the last one declared will be the one that is active.
You can however test the arguments that are passed to your function and implement many of the same types of behaviors that function overloading is designed to handle. In fact, in some cases you can do even more.
In your specific example:
function abc(s, t) {
// test to see if the t argument was passed
if (t !== undefined) {
console.log('was called as abc(s,t)');
} else {
console.log('was called as abc(s)');
}
}
abc('1'); // outputs 'was called as abc(s)'
abc('1', '2'); // outputs 'was called as abc(s,t)'
But, you can also get much, much more creative (and useful).
For example, the jQuery .css() method can be called five different ways.
.css( propertyName )
.css( propertyNames )
.css( propertyName, value )
.css( propertyName, function(index, value) )
.css( properties )
The code inside the .css() method examines the type and number of the arguments to figure out which way it is being called and therefore exactly what operation to carry out.
Let's look at how this could be done to figure out which of the 5 forms of this function are being used:
css: function(prop, value) {
// first figure out if we only have one argument
if (value === undefined) {
if (typeof prop === "string") {
// we have a simple request for a single css property by string name
// of this form: .css( propertyName )
} else if (Array.isArray(prop)) {
// we have a request for an array of properties
// of this form: .css( propertyNames )
} else if (typeof prop === "object") {
// property-value pairs of css to set
// of this form: .css( properties )
}
} else {
if (typeof value === "function") {
// of this form: .css( propertyName, function(index, value) )
} else {
// of this form: .css( propertyName, value )
}
}
}
You can also implement optional arguments. For example, jQuery's .hide() can accept many forms. One of the forms is .hide( [duration ] [, complete ] ) where both the duration and the completion function are optional. You can pass nothing, just a duration or both a duration and completion callback function. That could be implemented like this:
hide: function(duration, fn) {
// default the duration to zero if not present
duration = duration || 0;
// default the completion function to a dummy function if not present
fn = fn || function() {};
// now the code can proceed knowing that there are valid arguments for both
// duration and fn whether they were originally passed or not
}
I find one of the most useful ways of using these variable arguments are to allow code to support a variety of different argument types so that no matter what state your arguments are in, you can just pass them as you have them without having to convert them to some universal type. For example, in this implementation of a set object in javascript, the .add() method can take all of these different forms of arguments:
s.add(key)
s.add(key1, key2, key3)
s.add([key1, key2, key3])
s.add(key1, [key8, key9], key2, [key4, key5])
s.add(otherSet) // any other set object
s.add(arrayLikeObject) // such as an HTMLCollection or nodeList
This both accepts a variable number of arguments and it accepts a number of different types for each argument and it will adapt based on what is passed to it. So, you can initialize a set via a list of keys, an array of keys, from another set, from a pseudo array or any mixture of those types. Internally, the code just iterates through each argument that was passed to the function, checks the type of the argument and acts accordingly.
You can see the code here on GitHub for further info on how this is done.
I am getting more in to javascript development, and want to ensure I am following popular conventions.
Currently I have a library which consists of functions that can be passed either 1 model to operate on, or many models.
Given the climate that a few javascript libraries are very popular, I am curious; would I be conforming to the 'defacto standard' by achieving my 'single-item or list-of' requirement, by enumerating the arguments variable, or by allowing one of the arguments to be an array?
Scenario 1: argument enumeration
// passing a single entity to my function
sendMail( email, recipient1 );
// passing multiple entities to my function
sendMail( email, recipient1, recipient2 );
Scenario 2: entity argument is either single instance, or array
// pass a single entity
sendMail( email, recipient1 );
// passing multiple entities
sendMail( email, [recipient1, recipient2] );
I have seen areas of jQuery which use 'scenario 2', but I would still like to ask - which approach is the most popular, and why?
Thanks
[EDIT]
A couple of comments have followed the same vein, of using an arguments object - which is similar to 'scenario 2' - but I feel it introduces unnecessary complexity - the elements dont need to be named, because they are just a variable length list. I thought I would just add that here in case my question wasn't clear enough.
[EDIT]
I see code like this all through jQuery-1-7.js
queue: function( elem, type, data ) {
var q;
if ( elem ) {
type = ( type || "fx" ) + "queue";
q = jQuery._data( elem, type );
// Speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
if ( !q || jQuery.isArray(data) ) {
q = jQuery._data( elem, type, jQuery.makeArray(data) );
} else {
q.push( data );
}
}
return q || [];
}
}
[EDIT]
After some discussion with JP, I came up with this - which I'm not saying is the right choice, but it is very flexible...
lastArgumentAsParams: function()
{
var callerArgs = jQuery.makeArray(this.lastArgumentAsParams.caller.arguments);
// return empty set if caller has no arguments
if ( callerArgs.length == 0 )
return [];
callerArgs.splice(0, callerArgs.length - 1)
// remove all but the last argument
if ( callerArgs.length == 1 && jQuery.isArray(callerArgs[0]))
return callerArgs[0];
else
return callerArgs;
}
If you call this function at the beginning of any function - it will treat the last arg in the caller as a 'variable length argument' - supporting any of the conventions.
For example, I can use it like this
function sendEmail( body, recipients )
{
recipients = lastArgumentAsParams();
// foreach( recipient in recipients )...
}
Now, I can call 'sendEmail' in any of the following ways and it will work as expected
sendEmail('hello world', "bill#microsoft.com" );
sendEmail('hello world', "bill#microsoft.com", "steve#apple.com" );
sendEmail('hello world', ["bill#microsoft.com", "steve#apple.com"] );
I personally prefer using object literals for arguments to support named params, like this:
var myfunc = function(params){ //same as: function myfunc(params){....
alert(params.firstName);
alert(params.lastName);
};
myfunc({firstName: 'JP', lastName: 'Richardson'});
I think that it makes code very readable and order won't matter.
OR
You can also access the arguments object. Note, it's not an array, but it's "array-like". You can read about it here: http://javascriptweblog.wordpress.com/2011/01/18/javascripts-arguments-object-and-beyond/
Edit:
You seem to have a misunderstanding here. You're using the phrase "arguments object" and are thinking that it's the same as object literal notation. They are not.
The arguments object allows you to do this:
function myfunc(){
alert(arguments[0]); //JP
alert(arguments[1]); //Richardson
}
myfunc('JP', 'Richardson');
Does that help?
Another common way is to use object literal as variables:
myFunction(true, {option: value, option2: value});
I personally prefer this method for it is more verbose, and with javascript loose types, it gives you a better hint for what this variables is, and ignores order.
Backbone.js is using this as the preferred method.
To expand on the other answers, there are two main alternatives I usually see: optional arguments and keyword arguments. I don't remember seeing any good examples of the "array-using" idiom and it is kind of obsolete given how the arguments array is always available anyway.
Anyway, my rule of thumb is.
If I have many arguments, or the argument list is likely to change, or if the arguments don't have a good natural order, use the named arguments pattern
My favorite part about this style is that it is really flexible and future proof, while also being kind of self-documenting (in a smalltalk style).
foo({x1:'1', x2:'2', x3:'3'});
function foo(kwargs){
//I try to always copy the arguments back into variables.
//Its a little verbose but it helps documentation a lot and also
// lets me mutate the variables if I want to
var x1 = kwargs.x1,
x2 = kwargs.x2,
x3 = kwargs.x3;
}
If I have few arguments, that are not likely to change, and have a natural order to them, use a plain function (with the optional arguments last in the order)
foo(x1, x2);
foo(x1, x2, x3);
There are three main variations I can think right now of how to handle the optional arguments in the function:
var foo = function(x1, x2, x3){
//variation 1: truthy/falsy
// Short, but I tend to only use it when the variable stands
// for an object or other always-truthy kind of value
x3 = x3 || 'default_value';
//variation 2: using a special placeholder value for blank arguments.
// Usually this is null or undefined. (and undefined works if the arg is not passed too)
if(typeof x3 === 'undefined'){ x3 = 'default_value'; }
//variation 3: explicitly check the number of arguments
// I really like this one since it makes clear if the argument was passed or not.
if(arguments.length < 3){ x3 = 'default_value'; }
}
Also, there are so things I try to avoid:
Don't have functions that receive a large argument list. It can become a mess if they start becoming optional and you forget the order
foo(1, 2, null, null, 3, null, null); //ugh
Don't use fixed-length arrays to be tricky. They are redundant with no arrays at all and when I see an array I usually expect it to 1) be homogeneous and 2) be able to be as long as I want to
foo(true, [1, 2]); //should be foo(true, 1, 2)
Let's say I've got a method that takes some arguments and stores them as instance variables. If one of them is null, some code later on is going to crash. Would you modify the method to throw an exception if null arguments are provided and add unit tests to check that or not? If I do, it's slightly more complicated since javascript has many bad values (null, undefined, NaN, etc.) and since it has dynamic typing, I can't even check if the right kind of object was passed in.
I think it really depends on what sort of API you're unit testing. If this is a component designed and built for internal use only, and you know usage will be under certain constraints, it can be overkill to unit test for bad parameters. On the other hand, if you're talking about something for distribution externally, or which is used in a wide variety of situations, some of which are hard to predict, yes, checking for bad parameters is appropriate. It all depends on usage.
I think you really have 2 different questions here.
The first is what is the best practice for parameter input validation and the second is should your unit test handle test for these situations.
I would recommend that you either throw an Argument Exception for the parameter that was not supplied correctly to your function or some other variable/message that informs the calling function/user of the situation. Normally, you do not want to throw exceptions and should try to prevent the functions from even being called when you know they will fail.
For your unit test, you should definitely include NULL value tests to make sure a graceful result occurs.
JavaScript has instanceof and typeof that can help you check what kind of objects are being passed to your functions:
'undefined' == typeof noVariable; // true
var noVariable = null;
'undefined' == typeof noVariable; // false
typeof noVariable; // 'object'
noVariable === null; // true
var myArray = [];
typeof myArray; // 'object'
myArray instanceof Object; // true
myArray instanceof Array; // true
var myObject = {};
typeof myObject; // 'object'
myObject instanceof Object; // true
myObject instanceof Array; // false
You can use these to set some default "bad" values for your instance variables:
function myFunction(foo,bar) {
foo = foo instanceof Array ? foo : []; // If 'foo' is not an array, make it an empty one
bar = bar instanceof Number ? bar : 0;
// This loop should always exit without error, although it may never do a single iteration
for (var i=0; i<foo.length; i++) {
console.log(foo[i]);
}
// Should never fail
bar++;
}
The or operator is also very useful:
function myFunction(blat) {
var blat = blat||null; // If 'blat' is 0, '', undefined, NaN, or null, force it to be null
// You can be sure that 'blat' will be at least *some* kind of object inside this block
if (null!==blat) {
}
}
Also, don't forget that with JavaScript you can pass in fewer than or more than the expected number of parameters. You can check that too, if you like.
For creating robust and secure code, checking the edge cases is definitely important task. Positive and negative testing is always good for the quality. The lack of negative tests might bite you in the long run.
So I'd say it is better play it safe - do both. It's a bit more work, but if you can afford the time, then it'll be worth it. Taking the developer hat off and putting on the cracker hat can be very interesting sometimes.