Interviewer: “5 years, and still struggling with key existence checks in objects?”

The Pitfalls of ‘in’ and ‘hasOwnProperty’ in JavaScript

Well, this is not really an interview question but a concept that every web developer should know.

In JavaScript we use objects a lot, but when it comes it checking if a certain key exists in an object or not, if we use the simplest and quickest possible way to do the job, without knowing the consequences.

For frontend applications it might be forgiving but for backend application developed in node js, it can cause severe damange if any attacker find out that vulernability.

In this article we will be seeing

  1. what are the available ways to check if certain property exists in an object or not
  2. their shortcomings
  3. in the last what is be best possible way.

Way 1: Using Object.keys()

const obj = {};
const keyToFind = 'data';

if(Object.keys(obj).includes(keyToFind)) {
console.log('Key Found');
} else {
console.log('Key Not Found 404');
}

// This will output Key Not Found 404

This is what we want.

Drawback:

But wait, what If we define a key using Object.defineProperty

const obj = {};
Object.defineProperty('data', {value:true});
const keyToFind = 'data';

if(Object.keys(obj).includes(keyToFind)) {
console.log('Key Found');
} else {
console.log('Key Not Found 404');
}

// This will output Key Found

Wait What?

Yes, because keys added via Object.defineProperty are non-enumerable by default, and Object.keys method only show keys that are enumerable.

So we can’t rely on this method.

Way 2: Using in operator

const obj = {};
const keyToFind = 'data';

if(keyToFind in obj) {
console.log('Key Found');
} else {
console.log('Key Not Found 404');
}

// This will output Key Not Found 404

This is what we want.

Drawback:

But wait, what If the key which we have to check is constructor

const obj = {};
const keyToFind = 'constructor';

if(keyToFind in obj) {
console.log('Key Found');
} else {
console.log('Key Not Found 404');
}

// This will output Key Found

Wait What?

Yes because in operator searches for key in prototype chain, and guess what, we have constructor key available in prototype chain of each object.

Way 3: Using hasOwnProperty

hasOwnProperty solves the problem of prototype chain lookup, but it has it’s own drawbacks.

const obj = {};
const keyToFind = 'data';

if(obj.hasOwnProperty(keyToFind)) {
console.log('Key Found');
} else {
console.log('Key Not Found 404');
}

// This will output Key Not Found 404

This is what we want.

Drawback 1:

But wait, what If the object in which we have to check presence of key is created from null .

const obj = Object.create(null);
const keyToFind = 'data';

if(obj.hasOwnProperty(keyToFind)) {
console.log('Key Found');
} else {
console.log('Key Not Found 404');
}

// This will output Key Not Found 404

This will give us

VM2732:4 Uncaught TypeError: obj.hasOwnProperty is not a function
at <anonymous>:4:8

Because we have created object from null , we have cleared the prototype chain and now there are no inbuilt method attached to this object.

Drawback 2:

We can override hasownproperty .

const obj = {};

obj.hasOwnProperty = ()=> true;

const keyToFind = 'data';

if(obj.hasOwnProperty(keyToFind)) {
console.log('Key Found');
} else {
console.log('Key Not Found 404');
}

// This will output Key Found

Wait What?

Yes because we have implemented our own buggy version.

So What is the solution?

Object.hasOwn(Object, KeyToCheck);

Here comes Object.hasOwn to the rescue, Object.hasOwn is a static method that exists ob object and can be used to resolve all the problems which we have discussed above.

It comes as a part of ES2022. And is supported in all latest browsers.

const obj = {};
const keyToFind = 'data';

if(Object.hasOwn(obj, keyToFind)) {
console.log('Key Found');
} else {
console.log('Key Not Found 404');
}
// O/P Key Not Found 404

With constructor Key:

const obj = {};
const keyToFind = 'constructor';

if(Object.hasOwn(obj, keyToFind)) {
console.log('Key Found');
} else {
console.log('Key Not Found 404');
}
// O/P Key Not Found 404

With Object created from null:

const obj = Object.create(null);
const keyToFind = 'constructor';

if(Object.hasOwn(obj, keyToFind)) {
console.log('Key Found');
} else {
console.log('Key Not Found 404');
}
// O/P Key Not Found 404

With property added via Object.defineProperty.

const obj = {};
Object.defineProperty(obj,'data', {value:true});
const keyToFind = 'data';

if(Object.hasOwn(obj, keyToFind)) {
console.log('Key Found');
} else {
console.log('Key Not Found 404');
}

// This will output Key Found

Thanks for Reading, I hope this made you learn something new.

--

--