JavaScript isset Equivalent (3 methods)
Tags: javascript, webdev, beginners
Published: 2023-02-06 15:34:12

> ✋ **Update:** This post was originally published on my blog [decodingweb.dev](https://www.decodingweb.dev), where you can read the [latest version](https://www.decodingweb.dev/javascript-isset-equivalent) for a 💯 user experience. _~reza_

If you’re looking for the JavaScript "isset" equivalent, you’ve probably used it in PHP before and want the same functionality in JavaScript.

As you probably know, PHP’s `isset()` function checks a variable is declared and not null.

Although JavaScript doesn’t have an isset equivalent, there are several ways to check for the existence of a “potentially undeclared” variable before accessing it.

In this quick guide, we’ll explore three methods to check if a variable is declared:

- 1. <u>Method #1: Using the `typeof` operator</u>
- 2. <u>Method #2: Using `Object.prototype.hasOwnProperty()`</u>
- 3. <u>Method #3: Using the `in` operator</u>
- 4. <u>Bonus tip: Optional chaining</u>

Let’s take a closer look at each method.

## JavaScript isset with the `typeof` operator

The `typeof` operator takes an operand and returns the type of its value. The return value is always a string. So if the variable isn’t declared, typeof returns the string `'undefined'`.

```js
typeof 12
// output: 'number'

typeof 'Hello!'
// output: 'string'

typeof NonExistantVariable
// output: 'undefined'
```

This is a safe method to test potentially undeclared variables before accessing them:

```https://www.decodingweb.dev/label-htmlfor-property-explained
// if someVariable is declared ...
if (typeof someVariable !== 'undefined') {
    // Do something with the variable ...
}
```

⚠️ **Please note:** If you try to access a block-scoped local variable or constant (declared by `let` or `const`), you'll get a **ReferenceError** (even when using typeof). This is due to a concept called the temporal dead zone (TDZ).

A variable is in the temporal dead zone from the beginning of its block until it's declared and intialized.

```js
function myFunction() {
    if (typeof someVariable !== 'undefined') {
    // Do something here ...
    }

    // Declaring the variable after using typeof
    let someVariable = 'someValue'
}
```

This rule doesn't apply to variables defined with `var`, thanks to hoisting, where `var` declarations are executed before any other code, no matter where defined. 

Please note only the variable declaration is hoisted, but initialization (assignment of the value) happens until the code execution reaches the declaration line - until then, the variable remains `undefined`.

So to test if a variable is declared and not `null`:

```js
if (typeof someVariable !== 'undefined' && someVariable != null) {
 // Do something here ...
}
```

## JavaScript isset with `hasOwnProperty()`

If you want to check for the existence of a property inside an object, you can use `hasOwnProperty()`. This method returns `true` if the specified property is a direct property of the object - even if the value is `undefined`. 

```js
const artist = {
    name: 'Jimi Hendrix',
    instrument: 'Guitar'
}

console.log(artist.hasOwnProperty('name')) // output: true
console.log(artist.hasOwnProperty('instrumernt')) // output: true
console.log(artist.hasOwnProperty('genre')) // output: false
```

`Object.prototype.hasOwnProperty()` returns `false` if:

- The property doesn't exist
- Or has it been inherited

```js
let artist = {
    name: 'Jimi Hendrix'
}

console.log(artist.toString()) // [object Object]
console.log(artist.hasOwnProperty('toString')) // false
```

In the above example, we can call the `toString()` method because it's inherits the Object's prototype. However, when we check for its existence with `hasOwnProperty()`, we get `false` as it isn't a direct method. 

If you also want to check the value isn't nullish (just like PHP), you can do so like:

```js
const artist = {
    name: 'Jimi Hendrix',
    instrument: 'Guitar',
    genre: undefined,
    albums: null
}

console.log(artist.hasOwnProperty('genre') && artist.genre != null)
// output: false

console.log(artist.hasOwnProperty('albums') && artist.genre != null)
// output: false
```

Please note the `==` operator does an equality check rather than an identity check like the `===` operator.

Since most JavaScript objects inherit the prototype of Object, you can call `hasOwnProperty()` on arrays too:

```js
// Checking if an array index exists:
const fruits = ['apple',  'orange',  'banana']

fruits.hasOwnProperty(3)   // false
fruits.hasOwnProperty(2)   // true 
```

If you call `hasOwnProperty()` on objects with a null prototype, you'll get a TypeError.

The static method `Object.hasOwn()` has been introduced (since Chrome 93 and Firefox 92) as an alternative to `hasOwnProperty()`. This method is recommended over `hasOwnProperty()` because it also works with objects with a null prototype:

```js
const artist = Object.create(null)
artist.instrument = 'Guitar'

console.log(Object.hasOwn(artist, 'instrument'))
// output: true
```

## JavaScript isset with the `in` operator

The `in` operator checks if a property exists inside an object or its prototype chain. This is unlike the `hasOwnProperty()` and `Object.hasOwn()` methods that only consider the direct properties.

```js
const artist = {
    name: 'Jimi Hendrix',
    instrument: 'Guitar',
}

console.log('name' in artist) // output: true
console.log('toString' in artist) // output: true
```

You can also test array indices with the `in` operator:

```js
const fruits = ['apple', 'orange', 'banana']

console.log(2 in fruits) // output: true
console.log(6 in fruits) // output: false
```

Making a custom JavaScript isset function with the `in` operator should be easy:

```js
const artist = {
    name: 'Jimi Hendrix',
    instrument: 'guitar',
    genre: null,
    albums: undefined
}

function isset(object, identifier) {
    //Works for objects and arrays
    if (typeof object !== 'object') {
       throw new TypeError('The first argument is expected to be of type object')
    }

    return identifier in object && object[identifier] != null
}

console.log(isset(artist, 'name')) // output: true
console.log(isset(artist, 'instrument')) // output: true 
console.log(isset(artist, 'genre')) // output: false
console.log(isset(artist, 'albums')) // output: false
```

## Bonus tip: using optional chaining (`?.`)

The `?.` operator works like the `.` chaining operator with one difference: If a reference is nullish (null or undefined), the expression short-circuits with a return value of `undefined`.

```js
const obj = {
   firstLevel: {
      secondLevel: {
        value: 'some value'
      }
   }
}

console.log(obj.firstLevel?.secondLevel?.thirdLevel?.value)
// output: undefined

console.log(obj.firstLevel?.secondLevel?.value)
// output: some value
```

If we did it without the optional chaining, we'd get a TypeError.

```js
console.log(obj.firstLevel.secondLevel.thirdLevel.value)
// Uncaught TypeError: Cannot read properties of undefined (reading 'value')
```

The `?.` operator is a safe way of accessing nested properties when there's a possibility that a reference might be missing.

You can also use it with method calls; In that case, it'll return `undefined` if the method doesn't exist:

```js
let artist = {
    name: 'Jimi Hendrix'
}
const result = artist.perform?.();
console.log(result)
```

If you want to do optional chaining with arrays, you can use them with the bracket notation:

```js
const arr = [1, 2, 3, 4, 5]
console.log(arr?.[10]); // output: undefined
console.log(arr?.[2]); // output: 3
```

I think that does it! I hope you learned something new today.

Thanks for reading.

**❤️ You might like:**

- [Cannot find module error in Node.js (Fixed)](https://www.decodingweb.dev/cannot-find-module-error-in-node-js-fixed)
- [TypeError: map is not a function in JavaScript in JavaScript (Fixed)](https://www.decodingweb.dev/fix-map-is-not-a-function-error-in-javascript)
- [Add commas to numbers in JavaScript (Explained with examples)](https://www.decodingweb.dev/add-commas-to-numbers-in-javascript)
- [SyntaxError: Unexpected end of JSON input in JavaScript (Fixed)](https://www.decodingweb.dev/syntaxerror-unexpected-end-of-json-input-in-javascript)
- [How to fix "ReferenceError: document is not defined" in JavaScript](https://www.decodingweb.dev/how-to-solve-referenceerror-document-is-not-defined)
- [Label htmlFor Property Explained](https://www.decodingweb.dev/label-htmlfor-property-explained)