JavaScript isset() equivalent

954,420

Solution 1

I generally use the typeof operator:

if (typeof obj.foo !== 'undefined') {
  // your code here
}

It will return "undefined" either if the property doesn't exist or its value is undefined.

(See also: Difference between undefined and not being defined.)

There are other ways to figure out if a property exists on an object, like the hasOwnProperty method:

if (obj.hasOwnProperty('foo')) {
  // your code here
}

And the in operator:

if ('foo' in obj) {
  // your code here
}

The difference between the last two is that the hasOwnProperty method will check if the property exist physically on the object (the property is not inherited).

The in operator will check on all the properties reachable up in the prototype chain, e.g.:

var obj = { foo: 'bar'};

obj.hasOwnProperty('foo'); // true
obj.hasOwnProperty('toString'); // false
'toString' in obj; // true

As you can see, hasOwnProperty returns false and the in operator returns true when checking the toString method, this method is defined up in the prototype chain, because obj inherits form Object.prototype.

Solution 2

Age old thread, but there are new ways to run an equivalent isset().

ESNext (Stage 4 December 2019)

Two new syntax allow us to vastly simplify the use of isset() functionality:

Please read the docs and mind the browser compatibility.

Answer

See below for explanation. Note I use StandardJS syntax

Example Usage

// IMPORTANT pass a function to our isset() that returns the value we're
// trying to test(ES6 arrow function)
isset(() => some) // false

// Defining objects
let some = { nested: { value: 'hello' } }

// More tests that never throw an error
isset(() => some) // true
isset(() => some.nested) // true
isset(() => some.nested.value) // true
isset(() => some.nested.deeper.value) // false

// Less compact but still viable except when trying to use `this` context
isset(function () { return some.nested.deeper.value }) // false

Answer Function

/**
 * Checks to see if a value is set.
 *
 * @param   {Function} accessor Function that returns our value
 * @returns {Boolean}           Value is not undefined or null
 */
function isset (accessor) {
  try {
    // Note we're seeing if the returned value of our function is not
    // undefined or null
    return accessor() !== undefined && accessor() !== null
  } catch (e) {
    // And we're able to catch the Error it would normally throw for
    // referencing a property of undefined
    return false
  }
}

NPM Package

This answer function is available as the isset-php package on NPM. The package contains a few improvements such as type checking and supporting multiple arguments.

npm install --save isset-php

The full documentation is available in the README.

const isset = require('isset-php')
let val = ''

// This will evaluate to true so the text will be printed.
if (isset(() => val)) {
  console.log('This val is set so I will print.')
}

Explanation

PHP

Note that in PHP you can reference any variable at any depth - even trying to access a non-array as an array will return a simple true or false:

// Referencing an undeclared variable
isset($some); // false

$some = 'hello';

// Declared but has no depth(not an array)
isset($some); // true
isset($some['nested']); // false

$some = ['nested' => 'hello'];

// Declared as an array but not with the depth we're testing for
isset($some['nested']); // true
isset($some['nested']['deeper']); // false

JavaScript

In JavaScript, we don't have that freedom; we'll always get an error if we do the same because the engine is immediately attempting to access the value of deeper before we can wrap it in our isset() function so...

// Common pitfall answer(ES6 arrow function)
const isset = (ref) => typeof ref !== 'undefined'

// Same as above
function isset (ref) { return typeof ref !== 'undefined' }

// Referencing an undeclared variable will throw an error, so no luck here
isset(some) // Error: some is not defined

// Defining a simple object with no properties - so we aren't defining
// the property `nested`
let some = {}

// Simple checking if we have a declared variable
isset(some) // true

// Now trying to see if we have a top level property, still valid
isset(some.nested) // false

// But here is where things fall apart: trying to access a deep property
// of a complex object; it will throw an error
isset(some.nested.deeper) // Error: Cannot read property 'deeper' of undefined
//         ^^^^^^ undefined

More failing alternatives:

// Any way we attempt to access the `deeper` property of `nested` will
// throw an error
some.nested.deeper.hasOwnProperty('value') // Error
//   ^^^^^^ undefined

// Similar to the above but safe from objects overriding `hasOwnProperty`
Object.prototype.hasOwnProperty.call(some.nested.deeper, 'value') // Error
//                                        ^^^^^^ undefined

// Same goes for typeof
typeof some.nested.deeper !== 'undefined' // Error
//          ^^^^^^ undefined

And some working alternatives that can get redundant fast:

// Wrap everything in try...catch
try {
  if (isset(some.nested.deeper)) {
    // ...
  }
} catch (e) {}

try {
  if (some.nested.deeper !== undefined && some.nested.deeper !== null) {
    // ...
  }
} catch (e) {}

// Or by chaining all of the isset which can get long
isset(some) && isset(some.nested) && isset(some.nested.deeper) // false
//                        ^^^^^^ returns false so the next isset() is never run

Conclusion

All of the other answers - though most are viable...

  1. Assume you're only checking to see if the variable is not undefined which is fine for some use cases but can still throw an Error
  2. Assume you're only trying to access a top level property, which again is fine for some use cases
  3. Force you to use a less than ideal approach relative to PHP's isset()
    e.g. isset(some, 'nested.deeper.value')
  4. Use eval() which works but I personally avoid

I think I covered a lot of it. There are some points I make in my answer that I don't touch upon because they - although relevant - are not part of the question(e.g. short circuiting). If need be, though, I can update my answer with links to some of the more technical aspects based on demand.

I spent waaay to much time on this so hopefully it helps people out.

Thank-you for reading!

Solution 3

Reference to SOURCE

    module.exports = function isset () {
  //  discuss at: http://locutus.io/php/isset/
  // original by: Kevin van Zonneveld (http://kvz.io)
  // improved by: FremyCompany
  // improved by: Onno Marsman (https://twitter.com/onnomarsman)
  // improved by: Rafał Kukawski (http://blog.kukawski.pl)
  //   example 1: isset( undefined, true)
  //   returns 1: false
  //   example 2: isset( 'Kevin van Zonneveld' )
  //   returns 2: true

  var a = arguments
  var l = a.length
  var i = 0
  var undef

  if (l === 0) {
    throw new Error('Empty isset')
  }

  while (i !== l) {
    if (a[i] === undef || a[i] === null) {
      return false
    }
    i++
  }

  return true
}

phpjs.org is mostly retired in favor of locutus Here is the new link http://locutus.io/php/var/isset

Solution 4

if (!('foo' in obj)) {
  // not set.
}

Solution 5

This simple solution works, but not for deep object check.

function isset(str) {
    return window[str] !== undefined;
}
Share:
954,420
Bart van Heukelom
Author by

Bart van Heukelom

Professional software developer, online games, full stack but mostly backend. Electronics tinkerer. Maker. Freelance. See LinkedIn for more details. My UUID is 96940759-b98b-4673-b573-6aa6e38272c0

Updated on February 15, 2022

Comments

  • Bart van Heukelom
    Bart van Heukelom over 2 years

    In PHP you can do if(isset($array['foo'])) { ... }. In JavaScript you often use if(array.foo) { ... } to do the same, but this is not exactly the same statement. The condition will also evaluate to false if array.foo does exists but is false or 0 (and probably other values as well).

    What is the perfect equivalent of PHP's isset in JavaScript?

    In a broader sense, a general, complete guide on JavaScript's handling of variables that don't exist, variables without a value, etc. would be convenient.


    Update: 11 years and 11 months ago I posted this question, and wow, it still gets a lot of activity. Now, I'm pretty sure that when I wrote this, I only wanted to know how to check for the presence of a property in an associative array (a.k.a. dictionary), and as such the correct (for me) answers involve hasOwnProperty or the in operator. I wasn't interested in checking local or global variables.

    But while I remember that well, that intent is not quite clear in the question as written, or even directly contradicted by it! I never mentioned the associative array, and PHP's isset does also do those other things. Let this be a lesson to all of us about how important it is to properly state your requirements in a question, and also how global variables, local variables, object properties, dictionary keys and what-have-you aren't Huey, Dewey, and Louie.

    In the meantime (heh), many many people have provided answers to that effect as well, so for those of you who found this question through Google, well, I'm glad my vagueness helped in a way I guess. Anyway, just wanted to clarify that.

  • Matt Ball
    Matt Ball over 14 years
    Why use typeof rather than if( obj.foo !== undefined ) ?
  • Matt Ball
    Matt Ball over 14 years
    Ah. One day I will write a piece of truly cross-browser Javascript. Until then...
  • donut
    donut almost 14 years
    Shouldn't that be obj.hasOwnProperty('foo'), not obj.hasOwnProperty('bar')?
  • Christian C. Salvadó
    Christian C. Salvadó almost 14 years
    @alcuadrado: Thank you! -- Saludos hasta Argentina!
  • Enrique
    Enrique almost 13 years
    the problem with this is that you get an error when you try to check deeper properties, for example: obj.thisdoesntexist.foo !== undefined. In PHP you can use isset or empty and safely at any deep.
  • max4ever
    max4ever over 12 years
    IE8 doesn't has "hasOwnPropery"
  • Steven Pribilinskiy
    Steven Pribilinskiy about 10 years
    Exactly, PHP allows isset($abc->def->ghi->jkl) without raising an exception and halting the script, unlike JavaScript's typeof operator. You have to use something like try{ abc.def.ghi.jkl; isset=true } catch(e){ isset=false }
  • Steven Pribilinskiy
    Steven Pribilinskiy about 10 years
    This will raise an exception when calling isset(abc.def.ghi) in case if abc.def is undefined. However by combining this solution with the one that accepts a variable name in a form of a string, it will be identical to the PHP version.
  • Steven Pribilinskiy
    Steven Pribilinskiy about 10 years
    I have to extend my example to check for undefined properties: try{ abc.def.ghi.jkl; isset=(typeof abc.def.ghi.jkl !== 'undefined') } catch(e){ isset=false }
  • Halcyon
    Halcyon over 9 years
    @StevenPribilinskiy while that solution is functionally fine it's not a neat function call and it's a significant performance issue (throwing an Error is really expensive). You might consider something like: isset(abc, "def", "hgi", jkl") which can be implemented without a try-catch
  • Steven Pribilinskiy
    Steven Pribilinskiy over 9 years
    @Halcyon a real-world comparison with jsperf would be much appreciated
  • Halcyon
    Halcyon over 9 years
    jsperf.com/isset-trycatch-vs-loop It's a little bit more complicated. The try-catch method is severly asymmetrical. If it fails, it is 1000 (yes, one thousand) times slower. The loop method doesn't suffer from this asymmetry and performs well enough.
  • Steven Pribilinskiy
    Steven Pribilinskiy over 9 years
    Wow, what a diversion, good to know. The try-catch block is 577x times slower when it fails and this indeed will not compensate the 8-16x advantage over loops when it succeeds. Thanks for preparing the test.
  • Overflowh
    Overflowh over 9 years
    Since here we are talking about arrays, and since every array has a length property, wouldn't it be better to do so: if (typeof arr.length != "undefined") as a general way to check if an array is empty/not-set or not?
  • Boann
    Boann over 9 years
    Note that this is not exactly the same as PHP's isset, which returns false for variables explicitly set to null; whereas typeof returns object for variables set to null, as it does consider them defined. typeof x != "undefined" is more like using array_key_exists or property_exists.
  • Alexey Kosov
    Alexey Kosov almost 9 years
    @MattBall because "undefined" variable can be redefined with any value and it won't work then. var undefined = true;
  • Matt Ball
    Matt Ball almost 9 years
    @AlexeyKosov fortunately strict mode prevents assignment to undefined.
  • Gui Imamura
    Gui Imamura almost 9 years
    Invoking isset(var) with var unset: ReferenceError: var is not defined
  • Shree Krishna
    Shree Krishna over 8 years
    add some description too.
  • Bart van Heukelom
    Bart van Heukelom about 8 years
    6 years later, I can confidently say I know JavaScript very well. I find hasOwnProperty and the in operator to be the most equivalent to the PHP example from my question, which checks for the presence of a key in a simple dictionary without inheritance of any kind.
  • someone
    someone over 7 years
    @MattBall, to leave things more clear, undefined without quotes to get it working.
  • Julius
    Julius over 5 years
    This works for me, used it to check if a particular json response existed.
  • Vasilii Suricov
    Vasilii Suricov over 5 years
    Be careful when compare with str! typeof any !== 'unefined' because of typo. **it happens. to be sure use typeof foo === typeof undefined
  • ToolmakerSteve
    ToolmakerSteve over 4 years
    Minor nit: ` ? true : false` is superflous. The result of !== is already a boolean.
  • ToolmakerSteve
    ToolmakerSteve over 4 years
    As several earlier answers have mentioned, this will throw a ReferenceError if called with a variable that has never been declared.
  • ToolmakerSteve
    ToolmakerSteve over 4 years
    As several earlier answers have mentioned, this will throw a ReferenceError if called with a variable that has never been declared.
  • ToolmakerSteve
    ToolmakerSteve over 4 years
    As several earlier answers have mentioned, this will throw a ReferenceError if called with a variable that has never been declared. E.g. isset(someVar), where someVar has never been declared. However given that you do eval, you probably intend a string to be passed in. Show usage. Is your intended usage isset('someVar')? If so, this looks similar to this earlier answer - what about your answer is new?
  • Dave F
    Dave F over 3 years
    @MattBall That's a good question, which should have been addressed in the answer (but cannot be because the edit queue is full). For an undeclared variable v, v !== undefined throws an error, but typeof v !== 'undefined' returns false.
  • Hayden Thring
    Hayden Thring over 2 years
    I think this is actually a pretty simple and elegant solution to the need for an isset function, and bonus, it can detect infinite depth.
  • Lev Buchel
    Lev Buchel about 2 years
    This is wrong in so many ways..
  • Arsha
    Arsha about 2 years
    Thank you. I use your option isset() all the time until now. Currently the optional chaining is very interesting. Instead of if (isset(() => class.prop1.prop11)) {..}, now I use if (class.prop1?.prop11) {..}. Not sure that it will work the same on every case and every details but just work for my case.