I'm working on some existing code that looks something like this:
return this.getMyObject() && this.getMyObject().myArray[0];
As far as I can tell it is checking that the object returned by getMyObject() exists before returning the first item in it's myArray property. How does this work and is it good form?
Update: The reason for my question came from the confusion over how the && operator can be used to return a property value and not a boolean result. After further thought, to make it more readable I refactored the line to:
return this.getMyObject() ? this.getMyObject().myArray[0] : undefined;
Obviously I am assuming here that the myArray property will exist.
That code works because of type coercion. Some people will tell you its good and some people will say always truly check something using typeof
if (typeof someVariable === 'undefined')
Even in examples below the above check isn't enough. I don't know what is better but that code as far as I am concerned isn't how I write it myself but it is accepted with a lot of javascript developers. There are times that code in the correct conditions can still pass the first check and yet throw an error accessing the property. Depends how controlled your situation is that determines, to me, if you should or shouldn't allow it.
Example of passing first check and failing:
var myObject = 1;
var test = myObject && myObject.myArray[0];
Or as #JamesThorpe pointed out in comment above:
var myObject = {};
var test = myObject && myObject.myArray[0];
Also people familiar with some coding languages but not JS might look at that code and not understand what it means where checking with an if and then returning the value might be a bit more readable to others, which is also a plus I think.
It's correct form. If there is no object returned by this.getMyObject() then function will return false in another case second part of condition will be executed and returned as a result of function. It's good practice to check if object exists before calling any method on it, because an error could occur if not to do so.
But you should check an existence of an object only if you are not sure whether it exists.
Related
Have a look at the last two answers.
How can we determine without looking into any documentation that sliderinput.value is the right answer, and not sliderinput.value()?
Im coming from Java. Im used to call accessor methods.
What is "value" as opposed to "value()"?
What is sliderinput if not an object?
You can determine this by checking if value is a function:
typeof sliderinput.value === "function"
Javascript usually doesn't use getter functions like value(). If you want to use getters you can use the get syntax to create a getter function that can be called using normal property syntax. See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
In the context of this quiz you've posted, I suppose they just want you to know from the top of your head that value is a property in this case.
How can we determine without looking into any documentation that sliderinput.value is the right answer, and not sliderinput.value()?
You can try it and see.
You can test its type (with the typeof operator) to see if it is a function or something else.
… but reading the documentation, despite you dismissing it, is the correct approach.
Note that the attribute value of sliderinput is a string, so the options with parenthesis () are not valid and will throw an error. You could do that only if value were a function type variable, which is not.
Edit: as other members pointed out, you can use typeof to check the variable type; in this case it will be "string"
I've seen before that undefined semantically should only be used for variables that have been declared but not defined, and if a variable should at any point be set or unset, I should initially set it to null and check the variable against null rather than setting it back to undefined.
I'm wondering about the case where I am checking something that should be undefined, as in the case I am checking what an unset key in an object points to
i.e.
var eva = {'asuka': 2, 'rei': 0};
if I were to check eva['shinji'], I would have to check for undefined, because there are cases where I would not know all the possible keys that would be checked against.
I guess in this case, eva['shinji'] being undefined would be correct, though in the specific case of keys in objects, using ('shinji' in eva) would be best?
However, I have a feeling there may be other cases where objects that were unknown were checked against, that I could not use a 'in' for instead, but the case of object keys was most apparent to me.
In those cases, would it be best to check for undefined?
First of all, your statement is incorrect, should be:
var eva = {'asuka': 2, 'rei': ''};
Then you can find eva['asuka'] or eva.asuka will give 2.
If you want to check if a property inside an object.
There are multiple ways to do that.
You can simple check eva && eva.hasOwnProperty('asuka')
eva && typeof(eva.asuka) !== 'undefined'
3.
var found = false;
for (i in eva){
if (i == 'asuka') {
found = true;
break;
}
}
As mattclemens commented, if you do not understand the differences and best practices surrounding undefined vs null please check out the link he posted, or one of the other multitudes of blog/forum posts, books, or videos regarding this subject (i.e. duckduck something like "js best practices undefined null").
Based on the first paragraph of your question it seems you have a grasp on what they mean, and this question comes down to context...
I'm wondering about the case where I am checking something that should be undefined...
This seems like a loaded question to me. What does "should be undefined" mean? This tells me that your code never sets that property that "should be undefined" and you are assuming nothing else is setting it. But really, "should be undefined" doesn't make sense to me. You either know it's not because it's never been outside the current scope and you haven't defined it yourself, or you don't know and it's best practice to check whether it's defined before checking if it's null.
So I see this as 2 basic scenarios:
Internally/Privately created and used exclusively internal to code you control
Externally/Publicly created or crossing the public/private line
1. Internal/Private use only
In the first scenario the answer is simple: initialize the object with default values (falling back to null) for all properties that will ever exist on the object...
var eva = {'asuka': 2, 'rei': null};
...or since you have direct control over the object throughout its lifecycle, add properties explicitly as needed using the default operator...
eva.shinji = eva.shinji || null;
Then whenever you need to check the value of a specific property, your only concern is whether it is null. You will notice this strategy being employed in some of the most widely used js libraries, such as jQuery, where internal variables are only ever checked against null, or even assumed to exist within some contexts.
2. External/Public use at any point in the object's lifecycle
For objects you can't trust there are two approaches I would suggest, and which one is choosen depends, again, on the details of the context. If you are receiving some object, and will be using that object repeatedly or modifying the data you receive from it for internal use only, or if it is unsafe to change the value of the original object in any way, you may want to make your own copy of the object and then deal with that copy exclusively. Again, this is illustrated in libraries/frameworks, such as jQuery and AngularJS, where things like window and the undefined value itself, are passed in to the IIFE, and an internal copy is created/extended for internal use throughout the lifetime of the consumer.
However, this may be unnecessary overhead for your situation. Instead you could just verify the contents of eva when it crosses that external/internal boundary. The following example does so with the default operator.
function yourFunction(eva) {
eva = eva || {};
eva.asuka = eva.asuka || 2;
eva.rei = eva.rei || null;
}
Alternatively, you may have a string value or array of string values that are keys you wish to verify exist on the object. In that case please consider the following example using Object.keys(). This example also allows for the array of names of keys to be undefined.
function foo(eva, keysToFind) {
eva = eva || {};
keysToFind = keysToFind || ['asuka', 'shinji'];
var keysToCheck = Object.keys(eva);
for(var k in keysToFind) {
var keyName = keysToFind[k];
var keyIdx = keysToCheck.indexOf(keyName);
if(keyIdx == -1) {
eva[keyName] = null;
}
}
}
Finally, as RaymondM points out, you can take this a step further if you need to determine whether a property was added to the object literal, it's prototype, or inherited from a super/base class...
You can simple check eva && eva.hasOwnProperty('asuka')
Again, taking context in to consideration, if you have already identified the context as scenario 1 or 2 from above, and are checking any more than a single property's existence, then it will likely be more efficient to check for === null or typeof eva.asuka === 'undefined', respectively. Or even check if(eva && eva.asuka) { ... }, if you're certain asuka has been defined.
Is it wrong to return two different types from a JavaScript function? This is often the case in PHP. For instance PHP's strpos()-function returns an integer telling you the position or false if not found. In Java this would not be possible since it's not a loose typed language and the return type is defined with the function.
So would be be wrong to do the same in JavaScript?
E.g.
function num(x, y) {
if (x !== y) {return false;}
if (x < 5) {return 5;}
return x;
}
In above example we return an integer or boolean. But is it wrong? Would it make the life of the JavaScript engine harder and perhaps force it to de-optimize?
Or in another example, what if I have a function that creates an element and tries to put it into the DOM then returns the newly created element object. But if it can't find the parent element you send as an param it return false.
This is not wrong, since Javascript is dynamically typed.
However, it is often considered as bad taste: makes the code less readable, and might make it less efficiently translatable by JIT techniques.
It's not at all wrong. Your code will execute its job successfully. But the thing is it's not considered a very good programming practice. Though there are no hard and fast rules and in many situations such a methodology may be required, it's advisable to avoid this approach as far as applicable.
Secondly, you can consider re-factoring your code, so that it does only one thing. My suggestion would be to separate both the 'if's into two different methods.
It's not strict wrong, because javascript is dynamically typed. But if it happens, it could hide a wrong architecture of your function.
What happens in some cases?
In some case, JavaScript core returns null if there is no result. Is the case of .match function. In this case, null is something like "I've found nothing".
In other case it returns -1 (i.e. .indexOf). In this case it's appropriate because the return value should be an integer positive. -1 it's a way to tell us: "I've found nothing" or "I've not found a positive integer".
So why it returns in one case null and in other way -1 for tell us the same thing?
In the first case the match should return an Array (that's an Object).
In the second case the indexOf should return an integer. So -1 is more appropriate than null, because null it's an Object and not an integer.
Why not undefined? because undefined is something of undefined, like: "I've found nothing, and I don't know how tell you!". undefined generally is used when the function should returns a String but this string is not found. Returns "" is not elegant because it tell us: "I've found the String, and the string is empty".
Another case could be a function that returns a Boolean but in one case is undefined. So when you ask: "It's true or false?", it seems to says: "Neither!".
A beautiful example is this function:
isAlive(SchroedingersCat); // <--- undefined!!!
What if your function should be return a DOM element?
See what jQuery doing.
jQuery return always an Object. This object (instance of itself) could be empty or not.
var obj = $('#idElement') // <--- return always a jQuery object
if(obj.length == 1) {
// do something
}
This is an excellent trick in order to permit us to do a chain without force to check every time if we found something.
We have an object (referenced by data) and we want to retrieve the value of a nested property. Ideally, we would like to do it like so:
value = data.category3.section2.article4.title;
We cannot do this like so, because the above line throws a reference error if any of the mediate objects (category3, section2, or article4) are not defined (at the corresponding positions) inside the data object.
Now, to nullify any potential reference errors that might be thrown, we could just place the above line inside a try-catch statement:
try {
value = data.category3.section2.article4.title;
} catch (err ) {}
This works! However, I am not confident that relying on try-catch in such a way is a good practice. The alternative solution would be to manually traverse to the desired property value. I have written a compact utility function that accomplishes that:
function get( val, names ) {
names = names.split( '.' );
while ( val && names.length ) { val = val[ names.shift() ]; }
return val;
}
Now we can get the property value like so
value = get( data, 'category3.section2.article4.title' );
So, my question is:
Is the try-catch approach a valid solution? Or are there valid reasons why it should be avoided?
Btw, the try-catch approach is heavily biased in this thread: What's the simplest approach to check existence of deeply-nested object property in JavaScript?
Why not:
var value = data &&
data.category3 &&
data.category3.section2 &&
data.category3.section2.article4 &&
data.category3.section2.article4.title;
That is safe (if any of the objects in the traversal chain are not set, value will be null). That is a little neater than a bunch of if blocks, and avoids (?mis)using exceptions.
Another use of that method to provide a default value on failure:
var value = data &&
data.category3 &&
data.category3.section2 &&
data.category3.section2.article4 &&
data.category3.section2.article4.title || 'default value';
Both are fine. The only major differences between them I can think of are that
The try-catch may cause a debugger to unecessarily halt too often if you tell it to stop on all exceptions.
This is relevant you need to debug code that is swallowing exceptions. For example, some promise libraries wrap all callbacks in a try-catch block.
The string splitting version can't easily cope with properties that contain a dot in them
var x = {'.': {a: 17}};
try{ obj['.'].a }catch(e){}
get(/*???*/)
If you want something robust that avoids both pitfalls I would suggest a function that can (at least optionally) directly receive a list of properties.
get(val, ['prop1', 0, '.', 'category2']);
I think the differences here are going to be mostly contextual - it depends on the data you're trying to access and what you want to do with it.
For example, the second function will return equivalent undefined values for a variety of circumstances, including both data.category3 === undefined and data.category3.section2.article4.title === undefined. Using try/catch here tells you that you have an actual traversal error, rather than a property that hasn't been set, which you might want to handle differently.
Abusing try catch like this is a dirty hack.
Try catch is there to catch exceptions you throw. Exceptions are used for exceptional cases.
In this case both cases are wrong. You should never have to traverse data.category3.section2.article4.title; where every step can fail.
You should simply be able to assert that if data has a category then it should have a section, article and title.
I say refactor the code so you don't have multiple levels that can fail.
I have seen the answers here and I think that the traversing is your best move, but it looks quite bothersome. You can make a function that traverses it for you or you can use the almighty brototype library found at: https://github.com/letsgetrandy/brototype
This way you can do something like this:
if (Bro(data).doYouEven('category3.section2.article4.title')) {
value = data.category3.section2.article4.title;
}
or you can use a callback:
Bro(app).iDontAlways('category3.section2.article4.title')
.butWhenIdo(function(title){
value = title;
});
I think everyone should check this amazing library out, and code with great bro-ness.
If you dislike the brototype, you can indeed use your own get function.
I'm currently in the creation of a javascript function library. Mainly for my own use, but you can never be sure if someone else ends up using it in their projects, I'm atleast creating it as if that could happen.
Most methods only work if the variables that are passed are of the correct datatype. Now my question is: What is the best way to alert users that the variable is not of the correct type? Should one throw an error like this?
function foo(thisShouldBeAString){ //just pretend that this is a method and not a global function
if(typeof(thisShouldBeAString) === 'string') {
throw('foo(var), var should be of type string');
}
#yadayada
}
I know that javascript does internal type conversion, but this can create very weird results (ie '234' + 5 = '2345' but '234' * 1 = 234) and this could make my methods do very weird things.
EDIT
To make things extra clear: I do not wish to do type conversion, the variables passed should be of the correct type. What is the best way to tell the user of my library that the passed variables are not of the correct type?
The problem with type checking is that its actually quite hard to do. For example:-
var s = new String("Hello World!");
alert(typeof s);
What gets alerted? Ans: "object". Its true its a daft way to initialise a string but I see it quite often none-the-less. I prefer to attempt conversions where necessary or just do nothing.
Having said that in a Javascript environment in which I have total control (which is not true if you are simply providing a library) I use this set of prototype tweaks:-
String.prototype.isString = true;
Number.prototype.isNumber = true;
Boolean.prototype.isBoolean = true;
Date.prototype.isDate = true;
Array.prototype.isArray = true;
Hence testing for the common types can be as simple as:-
if (x.isString)
although you still need to watch out for null/undefined:-
if (x != null && x.isString)
In addition to avoiding the new String("thing") gotcha, this approach particularly comes into its own on Dates and Arrays.
Some small remarks on type checking - it's actually not that complicated:
Use typeof to check for primitives and instanceof to check for specific object types.
Example: Check for strings with
typeof x === 'string'
or
typeof x === 'string' || x instanceof String
if you want to include string objects.
To check for arrays, just use
x instanceof Array
This should work reasonably well (there are a few known exceptions - eg Firefox 3.0.5 has a bug where window instanceof Object === false although window.__proto__ instanceof Object === true).
edit: There are some further problems with detection of function objects:
In principle, you could both use typeof func === 'function' and func instanceof Function.
The catch is that in an unnamed browser from a big corporation these checks return the wrong results for some predefined functions (their type is given as 'object'). I know of no workaround for this - the checks only work reliably for user-defined functions...
edit2: There are also problems with objects passed from other windows/frames, as they will inherit from different global objects - ie instanceof will fail. Workarounds for built-in objects exists: For example, you can check for arrays via Object.prototype.toString.call(x) === '[object Array]'.
Libraries like jQuery do not inform the user of the error.
If a function is expecting a number, and a user passes a string, the function just returns without doing anything.
That way, you will avoid JavaScript errors popping up on a live website.
PS. Just make sure to always type check your inputted parameters, to avoid JavaScript errors being thrown.
How about throw:
https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/throw
Also type of does not distinguish between Array, Null, Object very well. Look at the funciton here: http://javascript.crockford.com/remedial.html, plus there are a few other ways to do it.
Personally I would not do the type checking since it is a step that will just add more processing time to the code. If you care about performance, you would want to chop off as many milliseconds of processing time as possible. Good Documentation will cure the need for the check.
What's about just to silently convert string to numeric datatype on function startup?
You always can determine the datatype of 'string'. Can't you?
You could check for some value like "debug=1" set. If there is - you could output errors like alerts. So in development mode user will see them, but on real site he will turn it off. Same way browser will not show you error message - you need to look at JS console.
Also there is FireBug. You could detect that and put FB debug Messages also.