- Javascript’s IN Operator Does Not Work With Strings
- Enjoyed This Post? ❤️ Share the Love With Your Friends! ❤️
- You Might Also Enjoy Some of My Other Posts
- in operator
- Try it
- Syntax
- Parameters
- Exceptions
- Description
- Examples
- Basic usage
- Using the in operator with deleted or undefined properties
- Inherited properties
- Using the in operator to implement branded checks
- Specifications
- Browser compatibility
- See also
- Found a content problem with this page?
- MDN
- Support
- Our communities
- Developers
- JavaScript In Operator
- The Syntax
- The Parameters
- Basic Use-Cases
- Deleted and Undefined
- Inherited properties
Javascript’s IN Operator Does Not Work With Strings
A while back, I learned that you could use the Javascript IN operator to test for object property existence. This was a great find because it tested for the presence of a key and not just the key’s value (which might evaluate to False). Since all core data types in Javascript extend the base Object in one way or another, I figured that the IN operator would work with all data types. This, however, turns out to be a poor assumption.
When I was updating my jQuery Template Markup Language (JTML) project, I wanted to make it so that the template constructor could accept either a jQuery collection (pointing to a Script tag) or a raw JTML markup string. In order to differentiate between these two types of objects, I put in the following code to test for a jQuery collection:
I figured if this evaluated to True, I was dealing with a jQuery collection; and, if this evaluated to False, I was dealing with a JTML string. This worked fine if I passed-in a jQuery collection, but it would error out if I passed-in a JTML string. As it turns out, the IN operator doesn’t seem to like working on String «objects.» To test this further, I set up the following demo code:
As you can see, I am trying to use Javascript’s IN operator on an instance of Object, Array, Date, Number, and String. When I run this code, I get the following console output:
Object false
Array true
Date false
Number false
invalid ‘in’ operand stringValue
[Break on this error] console.log( «String», («length» in stringValue) );
As you can see, the IN operator worked fine on everything except the String value. I am not sure why this is the case. Considering the fact that even Number works with the IN operator, I am not sure why String values are being treated so differently. Regardless, it might be a best practice to test the type of object before you use the IN operator on it.
NOTE: Although not demonstrated above, Boolean values also seem to be incompatible with the IN operator.
Want to use code from this post? Check out the license.
Enjoyed This Post? ❤️ Share the Love With Your Friends! ❤️
You Might Also Enjoy Some of My Other Posts
in operator
The in operator returns true if the specified property is in the specified object or its prototype chain.
Try it
Syntax
Parameters
A string or symbol representing a property name (non-symbols will be coerced to strings). Can also be a private property identifier.
Object to check if it (or its prototype chain) contains the property with specified name ( prop ).
Exceptions
Thrown if object is not an object (i.e. a primitive).
Description
The in operator tests if a string or symbol property is present in an object or its prototype chain. If you want to check for only non-inherited properties, use Object.hasOwn() instead.
A property may be present in an object but have value undefined . Therefore, x in obj is not the same as obj.x === undefined . To make in return false after a property is added, use the delete operator instead of setting that property’s value to undefined .
You can also use the in operator to check whether a particular private class field or method has been defined in an object. The operator returns true if the property is defined, and false otherwise. This is known as a branded check, because it returns true if and only if the object was created with that class constructor, after which you can safely access other private properties as well.
This is a special syntax — the left-hand side of the in operator is a property identifier instead of an expression, but unquoted (because otherwise it’s a string property, not a private property).
Because accessing private properties on objects unrelated to the current class throws a TypeError instead of returning undefined , this syntax allows you to shorten:
class C #x; static isC(obj) try obj.#x; return true; > catch return false; > > >
class C #x; static isC(obj) return #x in obj; > >
It also generally avoids the need for dealing with error handling just to access a private property that may be nonexistent.
However, the in operator still requires the private property to be declared beforehand in the enclosing class — otherwise, it would throw a SyntaxError («Private field ‘#x’ must be declared in an enclosing class»), the same one as when you try to access an undeclared private property.
class C foo() #x in this; > > new C().foo(); // SyntaxError: Private field '#x' must be declared in an enclosing class
Examples
Basic usage
The following examples show some uses of the in operator.
// Arrays const trees = ["redwood", "bay", "cedar", "oak", "maple"]; 0 in trees; // returns true 3 in trees; // returns true 6 in trees; // returns false "bay" in trees; // returns false (you must specify the index number, not the value at that index) "length" in trees; // returns true (length is an Array property) Symbol.iterator in trees; // returns true // Predefined objects "PI" in Math; // returns true // Custom objects const mycar = make: "Honda", model: "Accord", year: 1998 >; "make" in mycar; // returns true "model" in mycar; // returns true
You must specify an object on the right side of the in operator. For example, you can specify a string created with the String constructor, but you cannot specify a string literal.
const color1 = new String("green"); "length" in color1; // returns true const color2 = "coral"; // generates an error (color2 is not a String object) "length" in color2;
Using the in operator with deleted or undefined properties
If you delete a property with the delete operator, the in operator returns false for that property.
const mycar = make: "Honda", model: "Accord", year: 1998 >; delete mycar.make; "make" in mycar; // returns false const trees = ["redwood", "bay", "cedar", "oak", "maple"]; delete trees[3]; 3 in trees; // returns false
If you set a property to undefined but do not delete it, the in operator returns true for that property.
const mycar = make: "Honda", model: "Accord", year: 1998 >; mycar.make = undefined; "make" in mycar; // returns true
const trees = ["redwood", "bay", "cedar", "oak", "maple"]; trees[3] = undefined; 3 in trees; // returns true
The in operator will return false for empty array slots, even if accessing it directly returns undefined .
const empties = new Array(3); empties[2]; // returns undefined 2 in empties; // returns false
To avoid this, make sure a new array is always filled with non-empty values or not write to indexes past the end of array.
const empties = new Array(3).fill(undefined); 2 in empties; // returns true
Inherited properties
The in operator returns true for properties in the prototype chain. This may be undesirable if you are using objects to store arbitrary key-value pairs.
const ages = alice: 18, bob: 27 >; function hasPerson(name) return name in ages; > hasPerson("hasOwnProperty"); // true
You can use Object.hasOwn() to check if the object has the key.
const ages = alice: 18, bob: 27 >; function hasPerson(name) return Object.hasOwn(ages, name); > hasPerson("hasOwnProperty"); // false
Alternatively, you should consider using a null prototype object or a Map for storing ages , to avoid other bugs.
const ages = new Map([ ["alice", 18], ["bob", 27], ]); function hasPerson(name) return ages.has(name); > hasPerson("hasOwnProperty"); // false
Using the in operator to implement branded checks
The code fragment below demonstrates a static function that tells if an object was created with the Person constructor and therefore can perform other methods safely.
class Person #age; constructor(age) this.#age = age; > static isPerson(o) return #age in o; > ageDifference(other) return this.#age - other.#age; > > const p1 = new Person(20); const p2 = new Person(30); console.log(p1.ageDifference(p2)); // -10 console.log(Person.isPerson(p1)); // true if (Person.isPerson(p1) && Person.isPerson(p2)) console.log(p1.ageDifference(p2)); // -10 >
It helps to prevent the following case:
const p2 = >; p1.ageDifference(p2); // TypeError: Cannot read private member #age from an object whose class did not declare it
Without the in operator, you would have to use a try. catch block to check if the object has the private property.
You can also implement this as a @@hasInstance method of the class, so that you can use the instanceof operator to perform the same check (which, by default, only checks for the existence of Person.prototype in the object’s prototype chain).
class Person #age; constructor(age) this.#age = age; > static [Symbol.hasInstance](o) // Testing `this` to prevent false-positives when // calling `instanceof SubclassOfPerson` return this === Person && #age in o; > ageDifference(other) return this.#age - other.#age; > > const p1 = new Person(20); const p2 = new Person(30); if (p1 instanceof Person && p2 instanceof Person) console.log(p1.ageDifference(p2)); // -10 >
Specifications
Browser compatibility
BCD tables only load in the browser
See also
Found a content problem with this page?
This page was last modified on Apr 5, 2023 by MDN contributors.
Your blueprint for a better internet.
MDN
Support
Our communities
Developers
Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998– 2023 by individual mozilla.org contributors. Content available under a Creative Commons license.
JavaScript In Operator
On the MDN web docs, there is some good information. At it’s core, this operator looks pretty simple. But, as the quiz above shows, it’s not super intuitive.
The Syntax
The in operator is an built-in operator in JavaScript which is used to check whether a particular property exists in an object or not. It returns boolean value true if the specified property is in an object, otherwise it returns false . prop in object
The Parameters
A string or symbol representing a property name or array index (non-symbols will be coerced to strings).
Basic Use-Cases
// Arrays let people = ['bob', 'jen', 'patrick', 'anne', 'tim']; const person1 = 0 in people; // true const person2 = 3 in people; // true const person3 = 6 in people; // false const person4 = 'tom' in people; // false // (the index number must be specified, not the value at that index) const person5 = 'length' in people; // true // (length is a property of an Array) const person6 = Symbol.iterator in people; // true (arrays are iterable, works only in ES2015+) // Predefined Objects const hasPI = 'PI' in Math; // true // Custom objects let car = make: 'Ram', model: '1500', year: 2015 >; const hasMake = 'make' in car; // true const hasModel = 'model' in car; // true
An Object must specified on the right side of the in operator. A string created with the String constructor can be used, but a string literal cannot.
let color1 = new String('green'); const hasLength1 = 'length' in color1; // true let color2 = 'red'; const hasLength2 = 'length' in color2; // generates an error (color2 is not a String object)
Deleted and Undefined
If a property is deleted with the delete operator, the in operator returns false for that property. If a property is set to undefined but not deleted, the in operator returns true for that property. The in operator will return false for empty array slots. Even if accessing it directly returns undefined . To avoid this, make sure a new array is always filled with non-empty values or not write to indexes past the end of array.
let empty = new Array(3).fill(undefined) const isEmpty = 2 in empty // true
Inherited properties
The in operator returns true for properties in the prototype chain. (To check for only non-inherited properties, use Object.prototype.hasOwnProperty() instead.)
const hasToString = 'toString' in <> // true