简体   繁体   中英

Javascript checking undefined semantics

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 ie

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.

  1. You can simple check eva && eva.hasOwnProperty('asuka')
  2. 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 (ie 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:

  1. Internally/Privately created and used exclusively internal to code you control
  2. 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...

  1. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM