Question

How to Check if a Value Is an Object in JavaScript

javascripttypesjavascript-objects

Question

How can you determine whether a value is an object in JavaScript? In particular, how should the check handle special cases such as null, arrays, and functions?

Short Answer

You will learn why typeof value === "object" is not always enough, how to exclude null, and how to choose an object check that matches your goal. You will also see how to detect plain objects when arrays, dates, and custom class instances should not be accepted.

Concept

JavaScript has several values that can be described as objects, so the phrase "is an object" needs context.

The most common basic check is:

typeof value === "object" && value !== null

This works because most object values have a typeof result of "object". However, null is a historical JavaScript exception:

console.log(typeof null); // "object"

Therefore, a typeof check alone incorrectly treats null as an object.

A second important detail is that arrays, dates, regular expressions, maps, and class instances are also objects:

typeof [];              // "object"
typeof new Date();      // "object"
typeof /pattern/;       // "object"
typeof new Map();       // "object"

Functions are also object-like: they can have properties and methods, but typeof reports them as "function" rather than "object".

function greet() {}
greet.language = "en";

console.log(typeof greet); // "function"
console.log(greet.language); // "en"

For this reason, the correct check depends on what your code accepts:

  • Accept non-null object values, but not functions: use typeof value === "object" && value !== null.
  • Accept objects and functions: check whether the value is non-null and its type is "object" or "function".
  • Accept only ordinary object records such as API payloads: use a plain-object check.

Choosing the correct definition prevents validation bugs and makes a function's expected input clear.

Mental Model

Think of JavaScript values as items arriving at a sorting station.

  • Numbers, strings, booleans, undefined, symbols, and bigints are simple individual items: primitives.
  • Objects are containers that can hold named properties.
  • Arrays, dates, maps, and class instances are specialized kinds of containers.
  • Functions are machines that can run work, but JavaScript also lets them carry labelled properties, so they are object-like.
  • null means “no container exists.” Unfortunately, JavaScript's old typeof label mistakenly says it is an "object".

So typeof value === "object" is like trusting an old, occasionally incorrect sorting label. Add value !== null to reject the empty space, and use a stricter test when only a specific container type is valid.

Take Quiz

Syntax and Examples

For a general non-null object check:

function isObject(value) {
  return typeof value === "object" && value !== null;
}

console.log(isObject({ name: "Ada" })); // true
console.log(isObject([1, 2, 3]));        // true
console.log(isObject(new Date()));       // true
console.log(isObject(null));             // false
console.log(isObject("hello"));          // false
console.log(isObject(42));               // false
console.log(isObject(() => {}));         // false

This function returns true for non-null values whose typeof result is "object". It intentionally includes arrays and built-in objects, but it excludes functions.

If functions should count as object-like values, use this version:

function isObjectLike(value) {
  return value !== null &&
    (typeof value === "object" || typeof value === "function");
}

console.log(isObjectLike({}));       // true
console.log(isObjectLike(function () {})); // true
console.log(isObjectLike(null));     // false
console.log(isObjectLike("text"));   // false

If you need an ordinary object literal or an object created with Object.create(null), use a plain-object check:

function isPlainObject(value) {
  if (value === null || typeof value !== "object") {
    return false;
  }

  const prototype = Object.getPrototypeOf(value);
  return prototype === Object.prototype || prototype === null;
}

console.log(isPlainObject({ enabled: true })); // true
console.log(isPlainObject(Object.create(null))); // true
console.log(isPlainObject([]));                // false
console.log(isPlainObject(new Date()));        // false

class User {}
console.log(isPlainObject(new User()));        // false

Step by Step Execution

Consider this input-validation helper:

function isObject(value) {
  return typeof value === "object" && value !== null;
}

const input = null;
const result = isObject(input);

console.log(result);

Execution steps:

  1. input receives the value null.
  2. isObject(input) calls isObject(null).
  3. typeof value === "object" evaluates to true because typeof null is historically "object".
  4. value !== null evaluates to false because the value is exactly null.
  5. true && false evaluates to false.
  6. isObject returns false, and the console prints false.

Now use an array:

const input = ["red", "blue"];
console.log(isObject(input)); // true

Here typeof input === "object" is true, and the array is not null, so the result is true. If arrays are not valid for your use case, add an array-specific rule such as !Array.isArray(value) or use isPlainObject.

Real World Use Cases

  • Validating JSON-like API data: Confirm that a response section is an object before reading properties such as data.user.name.
  • Configuration options: Ensure a function receives an options object rather than null, a string, or a number.
  • Merging settings: Check that a value can be treated as a record before copying its properties.
  • Form processing: Validate nested submitted data before accessing optional fields.
  • Data transformation: Treat arrays separately from record objects because arrays are usually iterated, while objects are usually accessed by property names.

Example: validate options before using them.

function createConnection(options) {
  if (options === null || typeof options !== "object" || Array.isArray(options)) {
    throw new TypeError("options must be a plain options object");
  }

  return {
    host: options.host ?? "localhost",
    port: options.port ?? 3000
  };
}

console.log(createConnection({ host: "example.com" }));
Take Quiz

Real Codebase Usage

In production code, developers usually do not perform an object check merely to label a value. They check it before performing an operation that requires an object.

Guard clauses

A guard clause exits early when input is invalid. This keeps the main logic less nested.

function getDisplayName(user) {
  if (user === null || typeof user !== "object") {
    return "Guest";
  }

  return user.name ?? "Guest";
}

Validate the exact shape required

An object check does not prove required properties exist or have the correct types.

function canSendEmail(contact) {
  return contact !== null &&
    typeof contact === "object" &&
    typeof contact.email === "string" &&
    contact.email.length > 0;
}

Separate arrays from records

When code expects key-value settings, arrays normally should be rejected.

function updateSettings(settings) {
  if (!isPlainObject(settings)) {
    throw new TypeError("settings must be a plain object");
  }

  return { theme: "light", ...settings };
}

Handle unknown error values safely

JavaScript can throw any value, not just an Error object.

try {
  JSON.parse("not JSON");
} catch (error) {
  if (error !== null && typeof error === "object" && "message" in error) {
    console.error(error.message);
  } else {
    console.error("Unknown error", error);
  }
}

Use Object.hasOwn() when you specifically need an object's own property, rather than a property inherited from its prototype.

Common Mistakes

Forgetting that null has type "object"

Broken code:

function isObject(value) {
  return typeof value === "object";
}

console.log(isObject(null)); // true — usually unwanted

Fix it by excluding null:

return typeof value === "object" && value !== null;

Assuming arrays are not objects

console.log(typeof []); // "object"

If arrays are invalid, explicitly reject them:

const isRecord = value =>
  value !== null &&
  typeof value === "object" &&
  !Array.isArray(value);

For an exact ordinary-object test, prefer isPlainObject from the examples above.

Using instanceof Object as a general object test

({}) instanceof Object; // true

This can fail for objects created in another JavaScript realm, such as an iframe, because that realm has a different Object constructor. It also returns false for Object.create(null) because that object has no prototype. Prefer typeof plus a null check for broad validation.

Treating functions as ordinary objects by accident

Functions can have properties, but typeof fn is "function". Decide whether callback functions are acceptable. Use isObjectLike only when functions should be included.

Believing an object check validates data

This is not enough:

if (typeof user === "object" && user !== null) {
  sendEmail(user.email);
}

user.email may be missing or may not be a string. Validate the fields needed by the operation.

Using truthiness as an object check

if (value) {
  // This also accepts non-empty strings, numbers, and true.
}

Truthiness answers whether a value is truthy, not whether it is an object.

Comparisons

CheckAcceptsRejectsBest use
typeof value === "object"Objects, arrays, nullFunctions, primitivesAlmost never use alone because of null
value !== null && typeof value === "object"Non-null objects, arrays, dates, maps, class instancesnull, functions, primitivesBroad object validation
`value !== null && (typeof value === "object"typeof value === "function")`Objects and functions
Array.isArray(value)Arrays onlyPlain objects and other valuesDetecting a list
isPlainObject(value)Object literals and null-prototype objectsArrays, dates, class instancesJSON-like records and configuration
value instanceof SomeClassInstances from the same realm and constructor chainUnrelated valuesChecking a specific class type

Object.prototype.toString.call(value) can identify many built-in value categories:

Object.prototype.toString.call([]);         // "[object Array]"
Object.prototype.toString.call(new Date()); // "[object Date]"

However, this is usually unnecessary when Array.isArray, instanceof, or a targeted validation check communicates your intent more clearly.

Take Quiz

Cheat Sheet

// Broad check: objects, including arrays and dates; excludes null and functions
const isObject = value => value !== null && typeof value === "object";

// Object-like: includes callable functions too
const isObjectLike = value =>
  value !== null &&
  (typeof value === "object" || typeof value === "function");

// Arrays only
const isArray = Array.isArray(value);

// Plain object: object literal or Object.create(null)
const isPlainObject = value => {
  if (value === null || typeof value !== "object") return false;
  const prototype = Object.getPrototypeOf(value);
  return prototype === Object.prototype || prototype === null;
};

Key rules:

  • typeof null is "object"; always exclude null in a normal object check.
  • Arrays are objects, so use Array.isArray(value) to identify them.
  • Functions have typeof "function", even though they can have properties.
  • An object check does not validate required fields or property types.
  • Prefer the narrowest check that expresses what the function accepts.

FAQ

Why does typeof null return "object" in JavaScript?

It is a long-standing historical behavior in JavaScript. It cannot be changed without breaking existing code, so exclude it explicitly with value !== null.

Is an array an object in JavaScript?

Yes. typeof [] returns "object". Use Array.isArray(value) when you need to specifically detect arrays.

Do functions count as objects in JavaScript?

Functions are object-like because they can have properties, but typeof function () {} returns "function". Include that type only if your use case accepts functions.

What is the best general JavaScript object check?

For non-null objects, use value !== null && typeof value === "object". It is clear and works across realms such as iframes.

How do I check for a plain object in JavaScript?

Check that the value is non-null, has type "object", and has either Object.prototype or null as its prototype. This rejects arrays, dates, and class instances.

Should I use value instanceof Object?

Usually no for broad validation. It can behave unexpectedly with values from another realm and rejects null-prototype objects. Use it only when constructor/prototype identity is relevant.

Does checking for an object guarantee a property exists?

No. Check the individual property too, for example typeof value.email === "string".

Can JSON contain functions, dates, or maps?

No. Standard JSON data contains objects, arrays, strings, numbers, booleans, and null. Parsed JSON object records are generally plain objects, and JSON arrays are arrays.

Take Quiz

Mini Project

Description

Build a small settings normalizer for a command-line tool or web application. The function will accept a user-provided settings value, safely reject invalid types, and merge valid plain-object settings with defaults. This demonstrates why distinguishing plain objects from null, arrays, and dates matters.

Goal

Create a normalizeSettings function that returns safe settings or throws a useful error for invalid input.

Requirements

  1. Define default settings with a theme, page size, and notifications flag.
  2. Accept undefined and return the default settings.
  3. Accept only plain objects as custom settings.
  4. Reject null, arrays, dates, strings, and numbers with a TypeError.
  5. Merge valid custom settings over the defaults without modifying the default object.
Take Quiz

Keep learning

Related questions

View more