简体   繁体   中英

Checking for undefined

I am utterly confused. I know this has been asked a million times. And I have looked at questions like:

Test if something is not undefined in JavaScript

Now the problem is when doing the check I have found multiple things you can do.

I need to check if an object is an array, to do that I check if the "length" property is there. Now what one would I use?

 if (obj.length)

or

 if (obj.length === undefined)

or

 if (typeof obj.length === "undefined")

or

if (obj.length == null)

or something else?

I understand that === doesn't do any type conversion, and the if statement is just wanting a "truthy" or "falsey" value, meaning obj.length will return false if the length is 0, but that's not what we want. We want to now if it is defined. Which is why I go to type test. But which way is the best?

Here are some tests I did. 2, 3 and 4 work.

在此输入图像描述

Sorry for the stuff in between. I was doing it in the console for this page.

Short answer:

if (obj instanceof Array) {
    // obj is an array
}

Or, if you don't know whether obj is defined or not:

if ((typeof obj !== "undefined") && (obj instanceof Array)) {
    // obj is an array
}

To discuss why yours aren't quite right:

obj.anyProperty will throw a ReferenceError if obj is undefined. This affects all four of the things you put.

if (obj.length) will evaluate to false for an empty array, which isn't what you want. Because the length is 0 (a falsy value), it will falsely be inaccurate. This could also have issues if another object has a length property.

if (obj.length === undefined) will usually work, but it's frowned upon because undefined can be redefined. Someone could break your code by writing undefined = obj.length . This can also create false negatives; obj could happen to have a property called "length" and it would falsely call it an array.

if (typeof obj.length === "undefined") works fine, but could detect the same false negatives as the above.

if (obj.length == null) will work okay, but has the same bugs as above. In a double-equals ( == ), it matches null and undefined .

I would do `

obj instanceof Array

to check if obj is an array

http://jsfiddle.net/Tcjk4/

For what it's worth, here's how jQuery checks whether something is an array :

isArray: Array.isArray || function( obj ) {
    return jQuery.type(obj) === "array";
},

This uses ES5's Array.isArray if available, or a custom check in older browsers. jQuery makes this function accessible as $.isArray .

jQuery.type is basically an enhanced typeof that works around some limitations of the JavaScript language and browser bugs. Whereas typeof returns 'object' for anything object-like ( {} , [] , even null ), $.type returns the internal JavaScript [[Class]] property of the object.

In fact, this method of determining type is actually safer than instanceof :

Both instanceof and constructor look very innocent and seem like great ways to check if an object is an array.

The problems arise when it comes to scripting in multi-frame DOM environments. In a nutshell, Array objects created within one iframe do not share [[Prototype]]s with arrays created within another iframe. Their constructors are different objects and so both instanceof and constructor checks fail:

 var iframe = document.createElement('iframe'); document.body.appendChild(iframe); xArray = window.frames[window.frames.length-1].Array; var arr = new xArray(1,2,3); // [1,2,3] // Boom! arr instanceof Array; // false // Boom! arr.constructor === Array; // false 

More comment than answer.

While a test like object instanceof Array will work in most cases (it may fail where frames or inter–window communication are involved), it's a good idea to consider what you really need to test for and design the test accordingly. Testing explicitly whether an object is an array or not is almost always unnecessary.

In this case, it seems that you just want to use the length property for iterating over the object's numeric properties.

If that's the case, all you need to do is read the value of the length property and use it. Whether the property is missing, or hasn't been assigned a value, or has a value of undefined or 0 , you don't want to do the loop. Fortunately, you can do all of those tests in one go (and also skip processing if the value is Null or '' , which seems sensible too):

if (obj.length) {
  // iterate over numeric properties of obj
}

That will make the method generic, so it can be applied to any Object that has a suitable length property and some numeric properties (eg a jQuery object or an HTMLCollection object).

If you need some other feature of an array (say push or slice), you can also test for those.

If you are using the test as a logic fork (eg if it's an array do one thing, if it's a plain object do something else) then you should consider whether that's a sensible thing to do.

var sizeArrayOrObject = function(obj) {
    var size = 0, key;
    for (key in obj) {
        if (typeof obj.key === 'undefined') size++;
    }
    return size;
};

sizeArrayOrObject([]);  // 0
sizeArrayOrObject([5,6]);  // 2

sizeArrayOrObject({});  // 0
sizeArrayOrObject({id:8});  // 1

to use underscore.js http://underscorejs.org/#isObject

_.isArray(object) Returns true if object is an Array.

(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true

_.isObject(value) Returns true if value is an Object. Note that JavaScript arrays and functions are objects, while (normal) strings and numbers are not.

_.isObject({});
=> true
_.isObject(1);
=> false

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