JavaScript isset() equivalent
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...
- 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
- Assume you're only trying to access a top level property, which again is fine for some use cases
- Force you to use a less than ideal approach relative to PHP's
isset()
e.g.isset(some, 'nested.deeper.value')
- 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
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;
}
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, 2022Comments
-
Bart van Heukelom over 2 years
In PHP you can do
if(isset($array['foo'])) { ... }
. In JavaScript you often useif(array.foo) { ... }
to do the same, but this is not exactly the same statement. The condition will also evaluate to false ifarray.foo
does exists but isfalse
or0
(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 thein
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 over 14 yearsWhy use
typeof
rather thanif( obj.foo !== undefined )
? -
Matt Ball over 14 yearsAh. One day I will write a piece of truly cross-browser Javascript. Until then...
-
donut almost 14 yearsShouldn't that be
obj.hasOwnProperty('foo')
, notobj.hasOwnProperty('bar')
? -
Christian C. Salvadó almost 14 years@alcuadrado: Thank you! -- Saludos hasta Argentina!
-
Enrique almost 13 yearsthe 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 over 12 yearsIE8 doesn't has "hasOwnPropery"
-
Steven Pribilinskiy about 10 yearsExactly, PHP allows
isset($abc->def->ghi->jkl)
without raising an exception and halting the script, unlike JavaScript'stypeof
operator. You have to use something liketry{ abc.def.ghi.jkl; isset=true } catch(e){ isset=false }
-
Steven Pribilinskiy about 10 yearsThis will raise an exception when calling
isset(abc.def.ghi)
in case ifabc.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 about 10 yearsI 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 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 atry-catch
-
Steven Pribilinskiy over 9 years@Halcyon a real-world comparison with jsperf would be much appreciated
-
Halcyon over 9 yearsjsperf.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 over 9 yearsWow, 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 over 9 yearsSince 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 over 9 yearsNote that this is not exactly the same as PHP's
isset
, which returnsfalse
for variables explicitly set tonull
; whereastypeof
returnsobject
for variables set tonull
, as it does consider them defined.typeof x != "undefined"
is more like usingarray_key_exists
orproperty_exists
. -
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 almost 9 years@AlexeyKosov fortunately strict mode prevents assignment to
undefined
. -
Gui Imamura almost 9 yearsInvoking
isset(var)
withvar
unset:ReferenceError: var is not defined
-
Shree Krishna over 8 yearsadd some description too.
-
Bart van Heukelom about 8 years6 years later, I can confidently say I know JavaScript very well. I find
hasOwnProperty
and thein
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 over 7 years@MattBall, to leave things more clear, undefined without quotes to get it working.
-
Julius over 5 yearsThis works for me, used it to check if a particular json response existed.
-
Vasilii Suricov over 5 yearsBe careful when compare with str!
typeof any !== 'unefined'
because of typo. **it happens. to be sure usetypeof foo === typeof undefined
-
ToolmakerSteve over 4 yearsMinor nit: ` ? true : false` is superflous. The result of
!==
is already a boolean. -
ToolmakerSteve over 4 yearsAs several earlier answers have mentioned, this will throw a ReferenceError if called with a variable that has never been declared.
-
ToolmakerSteve over 4 yearsAs several earlier answers have mentioned, this will throw a ReferenceError if called with a variable that has never been declared.
-
ToolmakerSteve over 4 yearsAs several earlier answers have mentioned, this will throw a ReferenceError if called with a variable that has never been declared. E.g.
isset(someVar)
, wheresomeVar
has never been declared. However given that you doeval
, you probably intend a string to be passed in. Show usage. Is your intended usageisset('someVar')
? If so, this looks similar to this earlier answer - what about your answer is new? -
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, buttypeof v !== 'undefined'
returns false. -
Hayden Thring over 2 yearsI 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 about 2 yearsThis is wrong in so many ways..
-
Arsha about 2 yearsThank you. I use your option
isset()
all the time until now. Currently the optional chaining is very interesting. Instead ofif (isset(() => class.prop1.prop11)) {..}
, now I useif (class.prop1?.prop11) {..}
. Not sure that it will work the same on every case and every details but just work for my case.