How can I determine whether a variable is a string or something else in JavaScript?
The most reliable ways to check if a variable is a string in JavaScript include using the typeof operator, instanceof operator, and Object.prototype.toString.call() method. Each approach has different strengths and use cases depending on your specific needs and the JavaScript environment you’re working with.
Contents
- typeof Operator
- instanceof Operator
- Object.prototype.toString.call() Method
- String Constructor Check
- Comparing Methods
- Practical Examples
- Edge Cases and Considerations
typeof Operator
The typeof operator is the most straightforward method for checking if a variable is a string. It returns a string indicating the type of the unevaluated operand.
let myString = "Hello, World!";
let myNumber = 42;
let myObject = {};
let myNull = null;
let myUndefined = undefined;
console.log(typeof myString); // "string"
console.log(typeof myNumber); // "number"
console.log(typeof myObject); // "object"
console.log(typeof myNull); // "object" (this is a known quirk)
console.log(typeof myUndefined); // "undefined"
Advantages:
- Simple and fast
- Works with primitive values and objects
- No need to call any methods
Disadvantages:
typeof nullreturns"object"(this is a well-known bug in JavaScript)- Can be confused with boxed string objects
let boxedString = new String("Hello");
console.log(typeof boxedString); // "object"
instanceof Operator
The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor. For primitive strings, you need to use the String constructor.
let myString = "Hello, World!";
let myBoxedString = new String("Hello");
console.log(myString instanceof String); // false (primitive is not instance of String)
console.log(myBoxedString instanceof String); // true (boxed string is instance of String)
// For primitive strings, you can use:
console.log(myString instanceof Object); // false (primitives are not objects)
Advantages:
- Works well with object instances
- Can be extended in prototype chains
Disadvantages:
- Doesn’t work well with primitive strings
- Can be manipulated by changing prototype chains
- Returns
falsefor primitive values
Object.prototype.toString.call() Method
This method is the most reliable way to check types, including strings. It returns a string representing the object’s type.
let myString = "Hello, World!";
let myBoxedString = new String("Hello");
let myNumber = 42;
let myObject = {};
console.log(Object.prototype.toString.call(myString)); // "[object String]"
console.log(Object.prototype.toString.call(myBoxedString)); // "[object String]"
console.log(Object.prototype.toString.call(myNumber)); // "[object Number]"
console.log(Object.prototype.toString.call(myObject)); // "[object Object]"
Advantages:
- Works with both primitive and boxed strings
- Consistent across different JavaScript environments
- Not affected by prototype manipulation
Disadvantages:
- More verbose than
typeof - Slightly slower performance
- Returns a string that needs to be checked
function isString(value) {
return Object.prototype.toString.call(value) === '[object String]';
}
console.log(isString("Hello")); // true
console.log(isString(new String("Hi"))); // true
console.log(isString(42)); // false
String Constructor Check
You can also check if a value is a string by comparing it to the String constructor or using the String() function.
let myString = "Hello, World!";
let myBoxedString = new String("Hello");
console.log(myString.constructor === String); // true
console.log(myBoxedString.constructor === String); // true
// Using String() constructor
console.log(myString instanceof String); // false (primitive)
console.log(myBoxedString instanceof String); // true (boxed)
Important note: This method fails for null and undefined values because they don’t have a constructor property.
let myNull = null;
let myUndefined = undefined;
console.log(myNull?.constructor === String); // TypeError: Cannot read properties of null
console.log(myUndefined?.constructor === String); // TypeError: Cannot read properties of undefined
Comparing Methods
Here’s a comparison table of the different methods:
| Method | Primitive String | Boxed String | Null | Undefined | Performance |
|---|---|---|---|---|---|
typeof |
✅ "string" |
❌ "object" |
❌ "object" |
✅ "undefined" |
Fastest |
instanceof String |
❌ false |
✅ true |
❌ false |
❌ false |
Fast |
Object.prototype.toString.call() |
✅ "[object String]" |
✅ "[object String]" |
✅ "[object Null]" |
✅ "[object Undefined]" |
Medium |
constructor === String |
✅ true |
✅ true |
❌ Error | ❌ Error | Fast |
Practical Examples
Basic Type Checking Function
function isString(value) {
return typeof value === 'string';
}
console.log(isString("hello")); // true
console.log(isString(123)); // false
console.log(isString(null)); // false
console.log(isString(undefined)); // false
Comprehensive Type Checking Function
function isString(value) {
// Most reliable method
return Object.prototype.toString.call(value) === '[object String]';
}
// Alternative using typeof (faster but less comprehensive)
function isStringFast(value) {
return typeof value === 'string';
}
// Test with various types
console.log(isString("hello")); // true
console.log(isString(new String("hi"))); // true
console.log(isString(42)); // false
console.log(isString(null)); // false
console.log(isString(undefined)); // false
console.log(isString({})); // false
console.log(isString([])); // false
Handling Null and Undefined Safely
function safeIsString(value) {
if (value === null || value === undefined) {
return false;
}
return typeof value === 'string';
}
// Or using optional chaining
function safeIsStringModern(value) {
return typeof value?.constructor === 'function' &&
value.constructor === String;
}
Edge Cases and Considerations
String Objects vs Primitive Strings
let primitive = "hello";
let boxed = new String("hello");
console.log(typeof primitive); // "string"
console.log(typeof boxed); // "object"
console.log(primitive === boxed); // false
Cross-Environment Compatibility
Different JavaScript environments might have different behaviors:
// Node.js vs Browser differences
console.log(typeof document); // "object" in browser, "undefined" in Node.js
console.log(typeof window); // "object" in browser, "undefined" in Node.js
Performance Considerations
For performance-critical code, typeof is the fastest option:
// Benchmark different methods
console.time('typeof');
for (let i = 0; i < 1000000; i++) {
typeof "test" === "string";
}
console.timeEnd('typeof');
console.time('toString');
for (let i = 0; i < 1000000; i++) {
Object.prototype.toString.call("test") === "[object String]";
}
console.timeEnd('toString');
Security Considerations
Be aware that instanceof can be manipulated:
// Malicious code could modify String.prototype
String.prototype.valueOf = function() { return {}; };
let s = "hello";
console.log(s instanceof String); // true (but dangerous!)
Sources
- MDN Web Docs - typeof operator
- MDN Web Docs - instanceof operator
- MDN Web Docs - Object.prototype.toString()
- ECMAScript Language Specification - typeof operator
- JavaScript.info - Type conversions
Conclusion
- The
typeofoperator is the simplest and fastest method for checking primitive strings, but fails for boxed strings and has thenullquirk Object.prototype.toString.call()is the most reliable method that works consistently for both primitive and boxed strings, but is more verboseinstanceof Stringonly works with boxed string objects and returnsfalsefor primitive strings- For most use cases,
typeof value === 'string'provides the best balance of simplicity and performance - Consider your specific needs: if you need to handle boxed strings or require maximum reliability, use
Object.prototype.toString.call(value) === '[object String]' - Always consider the JavaScript environment and potential prototype manipulation when choosing your type-checking method
Choose the method that best fits your specific requirements, keeping in mind performance, reliability, and the types of values you need to handle.