Check if a value is an object in JavaScript

2018-12-31 21:21发布

How do you check if a value is an Object in JavaScript?

30条回答
情到深处是孤独
2楼-- · 2018-12-31 21:31

The Ramda functional library has a wonderful function for detecting JavaScript types.

Paraphrasing the full function:

function type(val) {
  return val === null      ? 'Null'      :
         val === undefined ? 'Undefined' :
         Object.prototype.toString.call(val).slice(8, -1);
}

I had to laugh when I realized how simple and beautiful the solution was.

Example usage from Ramda documentation:

R.type({}); //=> "Object"
R.type(1); //=> "Number"
R.type(false); //=> "Boolean"
R.type('s'); //=> "String"
R.type(null); //=> "Null"
R.type([]); //=> "Array"
R.type(/[A-z]/); //=> "RegExp"
R.type(() => {}); //=> "Function"
R.type(undefined); //=> "Undefined"
查看更多
时光乱了年华
3楼-- · 2018-12-31 21:31

i found a "new" way to do just this kind of type checking from this SO question: Why does instanceof return false for some literals?

from that, i created a function for type checking as follows:

function isVarTypeOf(_var, _type){
    try {
        return _var.constructor === _type;
    } catch(ex) {
        return false;         //fallback for null or undefined
    }
}

then you can just do:

console.log(isVarTypeOf('asdf', String));   // returns true
console.log(isVarTypeOf(new String('asdf'), String));   // returns true
console.log(isVarTypeOf(123, String));   // returns false
console.log(isVarTypeOf(123, Number));   // returns true
console.log(isVarTypeOf(new Date(), String));   // returns false
console.log(isVarTypeOf(new Date(), Number));   // returns false
console.log(isVarTypeOf(new Date(), Date));   // returns true
console.log(isVarTypeOf([], Object));   // returns false
console.log(isVarTypeOf([], Array));   // returns true
console.log(isVarTypeOf({}, Object));   // returns true
console.log(isVarTypeOf({}, Array));   // returns false
console.log(isVarTypeOf(null, Object));   // returns false
console.log(isVarTypeOf(undefined, Object));   // returns false
console.log(isVarTypeOf(false, Boolean));   // returns true

this is tested on Chrome 56, Firefox 52, Microsoft Edge 38, Internet Explorer 11, Opera 43

edit:
if you also want to check if a variable is null or undefined, you can use this instead:

function isVarTypeOf(_var, _type){
    try {
        return _var.constructor === _type;
    } catch(ex) {
        return _var == _type;   //null and undefined are considered the same
        // or you can use === if you want to differentiate them
    }
}

var a = undefined, b = null;
console.log(isVarTypeOf(a, undefined)) // returns true
console.log(isVarTypeOf(b, undefined)) // returns true
console.log(isVarTypeOf(a, null)) // returns true

update from inanc's comment: challenge accepted :D

if you want to loose compare objects you can try this way:

function isVarTypeOf(_var, _type, looseCompare){
    if (!looseCompare){
        try {
            return _var.constructor === _type;
        } catch(ex){
            return _var == _type;
        }
    } else {
        try{
            switch(_var.constructor){
                case Number:
                case Function:
                case Boolean:
                case Symbol:
                case Date:
                case String:
                case RegExp:
                    // add all standard objects you want to differentiate here
                    return _var.constructor === _type;
                case Error:
                case EvalError:
                case RangeError:
                case ReferenceError:
                case SyntaxError:
                case TypeError:
                case URIError:
                    // all errors are considered the same when compared to generic Error
                    return (_type === Error ? Error : _var.constructor) === _type;
                case Array:
                case Int8Array:
                case Uint8Array:
                case Uint8ClampedArray:
                case Int16Array:
                case Uint16Array:
                case Int32Array:
                case Uint32Array:
                case Float32Array:
                case Float64Array:
                    // all types of array are considered the same when compared to generic Array
                    return (_type === Array ? Array : _var.constructor) === _type;
                case Object:
                default:
                    // the remaining are considered as custom class/object, so treat it as object when compared to generic Object
                    return (_type === Object ? Object : _var.constructor) === _type;
            }
        } catch(ex){
            return _var == _type;   //null and undefined are considered the same
            // or you can use === if you want to differentiate them
        }
    }
}

that way, you can do just like inanc's comment:

isVarTypeOf(new (function Foo(){}), Object); // returns false
isVarTypeOf(new (function Foo(){}), Object, true); // returns true

or

Foo = function(){};
Bar = function(){};
isVarTypeOf(new Foo(), Object);   // returns false
isVarTypeOf(new Foo(), Object, true);   // returns true
isVarTypeOf(new Bar(), Foo, true);   // returns false
isVarTypeOf(new Bar(), Bar, true);   // returns true
isVarTypeOf(new Bar(), Bar);    // returns true
查看更多
宁负流年不负卿
4楼-- · 2018-12-31 21:33

Let's define "object" in Javascript. According to the MDN docs, every value is either an object or a primitive:

primitive, primitive value

A data that is not an object and does not have any methods. JavaScript has 5 primitive datatypes: string, number, boolean, null, undefined.

What's a primitive?

  • 3
  • 'abc'
  • true
  • null
  • undefined

What's an object (i.e. not a primitive)?

  • Object.prototype
  • everything descended from Object.prototype
    • Function.prototype
      • Object
      • Function
      • function C(){} -- user-defined functions
    • C.prototype -- the prototype property of a user-defined function: this is not Cs prototype
      • new C() -- "new"-ing a user-defined function
    • Math
    • Array.prototype
      • arrays
    • {"a": 1, "b": 2} -- objects created using literal notation
    • new Number(3) -- wrappers around primitives
    • ... many other things ...
  • Object.create(null)
  • everything descended from an Object.create(null)

How to check whether a value is an object

instanceof by itself won't work, because it misses two cases:

// oops:  isObject(Object.prototype) -> false
// oops:  isObject(Object.create(null)) -> false
function isObject(val) {
    return val instanceof Object; 
}

typeof x === 'object' won't work, because of false positives (null) and false negatives (functions):

// oops: isObject(Object) -> false
function isObject(val) {
    return (typeof val === 'object');
}

Object.prototype.toString.call won't work, because of false positives for all of the primitives:

> Object.prototype.toString.call(3)
"[object Number]"

> Object.prototype.toString.call(new Number(3))
"[object Number]"

So I use:

function isObject(val) {
    if (val === null) { return false;}
    return ( (typeof val === 'function') || (typeof val === 'object') );
}

@Daan's answer also seems to work:

function isObject(obj) {
  return obj === Object(obj);
}

because, according to the MDN docs:

The Object constructor creates an object wrapper for the given value. If the value is null or undefined, it will create and return an empty object, otherwise, it will return an object of a type that corresponds to the given value. If the value is an object already, it will return the value.


A third way that seems to work (not sure if it's 100%) is to use Object.getPrototypeOf which throws an exception if its argument isn't an object:

// these 5 examples throw exceptions
Object.getPrototypeOf(null)
Object.getPrototypeOf(undefined)
Object.getPrototypeOf(3)
Object.getPrototypeOf('abc')
Object.getPrototypeOf(true)

// these 5 examples don't throw exceptions
Object.getPrototypeOf(Object)
Object.getPrototypeOf(Object.prototype)
Object.getPrototypeOf(Object.create(null))
Object.getPrototypeOf([])
Object.getPrototypeOf({})
查看更多
笑指拈花
5楼-- · 2018-12-31 21:34

The official underscore.js uses this check to find out if something is really an object

// Is a given variable an object?
_.isObject = function(obj) {
  return obj === Object(obj);
};
查看更多
怪性笑人.
6楼-- · 2018-12-31 21:34

Object.prototype.toString.call(myVar) will return:

  • "[object Object]" if myVar is an object
  • "[object Array]" if myVar is an array
  • etc.

For more information on this and why it is a good alternative to typeof, check out this article.

查看更多
公子世无双
7楼-- · 2018-12-31 21:35

Little late... for "plain objects" (i mean, like {'x': 5, 'y': 7}) i have this little snippet:

function isPlainObject(o) {
   return ((o === null) || Array.isArray(o) || typeof o == 'function') ?
           false
          :(typeof o == 'object');
}

It generates the next output:

console.debug(isPlainObject(isPlainObject)); //function, false
console.debug(isPlainObject({'x': 6, 'y': 16})); //literal object, true
console.debug(isPlainObject(5)); //number, false
console.debug(isPlainObject(undefined)); //undefined, false
console.debug(isPlainObject(null)); //null, false
console.debug(isPlainObject('a')); //string, false
console.debug(isPlainObject([])); //array?, false
console.debug(isPlainObject(true)); //bool, false
console.debug(isPlainObject(false)); //bool, false

It always works for me. If will return "true" only if the type of "o" is "object", but no null, or array, or function. :)

查看更多
登录 后发表回答