What can be object keys and values in JavaScript?

👨‍💻 Frontend Developer 🟡 Often Asked 🎚️ Easy
#JavaScript #Objects

Brief Answer

Object keys can be strings or Symbol, while values can be any data types.

const obj = {
  // Keys (automatically converted to strings)
  "string": "value",
  42: "number as key",
  true: "boolean as key",
  
  // Values (any types)
  name: "string",
  age: 25,
  isActive: true,
  items: [1, 2, 3],
  nested: { a: 1 },
  method: function() { return "function"; }
};
 
// Symbol as key
const sym = Symbol('id');
obj[sym] = "Symbol value";

Important features:

  • Keys are automatically converted to strings (except Symbol)
  • Values can be any type without limitations
  • Symbol is the only key type that doesn’t convert to string

What can be object keys

Strings (primary type)

Strings are the natural type for object keys:

const obj = {
  "firstName": "John",
  "last-name": "Doe",
  "age in years": 30,
  "": "empty string is also valid",
  " ": "space as key",
  "123": "string of numbers"
};
 
console.log(obj["firstName"]);     // "John"
console.log(obj["last-name"]);     // "Doe"
console.log(obj[""]);              // "empty string is also valid"

Numbers (converted to strings)

Numbers are automatically converted to strings:

const obj = {
  42: "value",
  3.14: "pi",
  0: "zero",
  -5: "negative"
};
 
// All numeric keys become strings
console.log(obj["42"]);    // "value"
console.log(obj[42]);      // "value" (also works)
console.log(typeof Object.keys(obj)[0]); // "string"
 
// Conversion check
console.log("42" in obj);  // true
console.log(42 in obj);    // true (auto-conversion)

Boolean values (converted to strings)

Boolean values are also converted to strings:

const obj = {
  true: "truth",
  false: "falsy"
};
 
console.log(obj["true"]);  // "truth"
console.log(obj[true]);    // "truth"
console.log(obj["false"]); // "falsy"
console.log(obj[false]);   // "falsy"
 
// Keys became strings
console.log(Object.keys(obj)); // ["true", "false"]

undefined and null (converted to strings)

Even undefined and null become strings:

const obj = {
  undefined: "not defined",
  null: "emptiness"
};
 
console.log(obj["undefined"]); // "not defined"
console.log(obj[undefined]);   // "not defined"
console.log(obj["null"]);      // "emptiness"
console.log(obj[null]);        // "emptiness"

Symbol (not converted!)

Symbol is the only key type that is NOT converted to string:

const sym1 = Symbol('id');
const sym2 = Symbol('id');
const sym3 = Symbol.for('global');
 
const obj = {
  [sym1]: "first symbol",
  [sym2]: "second symbol",
  [sym3]: "global symbol",
  "Symbol(id)": "this is NOT a symbol, but a string!"
};
 
console.log(obj[sym1]);        // "first symbol"
console.log(obj[sym2]);        // "second symbol"
console.log(obj["Symbol(id)"]); // "this is NOT a symbol, but a string!"
 
// Symbol keys don't appear in Object.keys()
console.log(Object.keys(obj));           // ["Symbol(id)"]
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(id), Symbol(id), Symbol(global)]

Objects (converted via toString)

Objects as keys are converted via toString():

const obj1 = { name: "object1" };
const obj2 = { name: "object2" };
const arr = [1, 2, 3];
 
const container = {
  [obj1]: "value for obj1",
  [obj2]: "value for obj2", // Will overwrite the previous!
  [arr]: "value for array"
};
 
// All objects became "[object Object]"
console.log(Object.keys(container)); // ["[object Object]", "1,2,3"]
console.log(container[obj1]);         // "value for obj2" (!)
console.log(container["[object Object]"]); // "value for obj2"

What can be object values

Primitive types

Any primitives can be values:

const primitives = {
  stringValue: "string",
  numberValue: 42,
  booleanValue: true,
  undefinedValue: undefined,
  nullValue: null,
  symbolValue: Symbol('value'),
  bigintValue: 123n
};

Objects and arrays

Objects, arrays and other complex types:

const complex = {
  array: [1, 2, 3],
  object: { nested: true },
  date: new Date(),
  regexp: /pattern/gi,
  map: new Map([['key', 'value']]),
  set: new Set([1, 2, 3]),
  weakMap: new WeakMap(),
  promise: Promise.resolve("done")
};

Functions

Functions are full-fledged object values:

const withFunctions = {
  // Regular function
  regularFunction: function() {
    return "regular function";
  },
  
  // Arrow function
  arrowFunction: () => "arrow function",
  
  // Method (shorthand syntax)
  method() {
    return "object method";
  },
  
  // Async function
  async asyncMethod() {
    return "async method";
  },
  
  // Generator function
  *generatorMethod() {
    yield "generator";
  }
};

Special objects

DOM elements, classes and other special objects:

const special = {
  // DOM element (in browser)
  element: document.createElement('div'),
  
  // Class constructor
  MyClass: class MyClass {
    constructor(name) {
      this.name = name;
    }
  },
  
  // Error object
  error: new Error("something went wrong"),
  
  // Buffer (in Node.js)
  // buffer: Buffer.from('hello')
};

Features and limitations

Key conversion

Key TypeConversionExampleResult
stringNo change"key""key"
numberTo string42"42"
booleanTo stringtrue"true"
undefinedTo stringundefined"undefined"
nullTo stringnull"null"
SymbolNo changeSymbol('id')Symbol(id)
ObjecttoString(){}"[object Object]"
Arrayjoin(’,‘)[1,2]"1,2"

Key ordering

Keys have a specific order:

const obj = {
  "3": "three",
  "1": "one", 
  "2": "two",
  "b": "bee",
  "a": "ay"
};
 
console.log(Object.keys(obj)); // ["1", "2", "3", "b", "a"]
// Numeric keys are sorted, string keys follow insertion order

Symbol keys are special

Symbol keys have special behavior:

const sym = Symbol('test');
const obj = {
  regular: "regular key",
  [sym]: "symbol key"
};
 
// Not displayed in standard methods
console.log(Object.keys(obj));        // ["regular"]
console.log(Object.values(obj));      // ["regular key"] 
console.log(Object.entries(obj));     // [["regular", "regular key"]]
 
// Special methods for Symbol
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(test)]
console.log(Reflect.ownKeys(obj)); // ["regular", Symbol(test)]

Practical examples

Using numbers as keys

// Array-like object indices
const arrayLike = {
  0: "first",
  1: "second", 
  2: "third",
  length: 3
};
 
// Configuration by ID
const configs = {
  1: { name: "dev", debug: true },
  2: { name: "prod", debug: false },
  999: { name: "test", debug: true }
};

Symbol for private properties

const PRIVATE_ID = Symbol('privateId');
const PRIVATE_METHOD = Symbol('privateMethod');
 
class User {
  constructor(name) {
    this.name = name;
    this[PRIVATE_ID] = Math.random();
  }
  
  [PRIVATE_METHOD]() {
    return "private method";
  }
  
  getId() {
    return this[PRIVATE_ID];
  }
}
 
const user = new User("John");
console.log(user.name);        // "John"
console.log(user.getId());     // 0.123456789
console.log(Object.keys(user)); // ["name"] (Symbol keys are hidden)

Dynamic keys

// Creating object with dynamic keys
function createObject(keyPrefix, values) {
  const obj = {};
  
  values.forEach((value, index) => {
    obj[`${keyPrefix}_${index}`] = value;
  });
  
  return obj;
}
 
const result = createObject("item", ["a", "b", "c"]);
console.log(result); // { item_0: "a", item_1: "b", item_2: "c" }

Computed properties

const prefix = "user";
const id = 123;
 
const obj = {
  // Computed keys
  [`${prefix}_${id}`]: "value",
  [prefix.toUpperCase()]: "UPPERCASE",
  [`is${prefix.charAt(0).toUpperCase() + prefix.slice(1)}Active`]: true
};
 
console.log(obj); 
// {
//   user_123: "value",
//   USER: "UPPERCASE", 
//   isUserActive: true
// }

Common mistakes

1. Objects as keys

// ❌ Problem: all objects become "[object Object]"
const map = {};
const key1 = { id: 1 };
const key2 = { id: 2 };
 
map[key1] = "value 1";
map[key2] = "value 2"; // Will overwrite the previous!
 
console.log(map); // { "[object Object]": "value 2" }
 
// ✅ Solution: use Map
const map2 = new Map();
map2.set(key1, "value 1");
map2.set(key2, "value 2");
 
console.log(map2.get(key1)); // "value 1"
console.log(map2.get(key2)); // "value 2"

2. Loss of Symbol keys

const sym = Symbol('test');
const obj = {
  regular: "regular",
  [sym]: "symbol"
};
 
// ❌ Symbol keys are lost in JSON
const json = JSON.stringify(obj);
console.log(json); // {"regular":"regular"}
 
const restored = JSON.parse(json);
console.log(restored[sym]); // undefined
 
// ✅ Consider this during serialization
function serializeWithSymbols(obj) {
  const symbols = Object.getOwnPropertySymbols(obj);
  const result = { ...obj };
  
  symbols.forEach(sym => {
    result[sym.toString()] = obj[sym];
  });
  
  return result;
}

3. Unexpected key conversion

// ❌ Unexpected behavior
const obj = {};
obj[1] = "one";
obj["1"] = "string one"; // Will overwrite the previous!
 
console.log(obj); // { "1": "string one" }
 
// ✅ Be careful with key types
const safeObj = new Map();
safeObj.set(1, "number one");
safeObj.set("1", "string one");
 
console.log(safeObj.get(1));   // "number one"
console.log(safeObj.get("1")); // "string one"

Object vs Map comparison

FeatureObjectMap
Key typesstring, SymbolAny types
Sizemanual.size
IterationObject.keys()for...of
PerformanceOptimized for recordsOptimized for frequent additions/deletions
JSON serializationYesNo (requires conversion)
PrototypeHas (Object.prototype)Clean (Object.create(null))
// When to use Object
const config = {
  apiUrl: "https://api.example.com",
  timeout: 5000,
  retries: 3
};
 
// When to use Map
const cache = new Map();
const element1 = document.getElementById('btn1');
const element2 = document.getElementById('btn2');
 
cache.set(element1, { clicks: 5 });
cache.set(element2, { clicks: 2 });
cache.set("global", { lastUpdate: Date.now() });

Practice problems

Problem 1: Key types

const obj = {
  1: "a",
  "1": "b", 
  true: "c",
  "true": "d"
};
 
console.log(Object.keys(obj).length);
Answer `2` — numeric key `1` and boolean `true` are converted to strings, so duplicate keys overwrite previous ones.

Problem 2: Symbol keys

const sym = Symbol('key');
const obj = {
  [sym]: "symbol value",
  key: "string value"
};
 
console.log(Object.keys(obj));
console.log(Object.getOwnPropertySymbols(obj));
Answer `["key"]` and `[Symbol(key)]` — Symbol keys don't appear in `Object.keys()`, only in `Object.getOwnPropertySymbols()`.

Problem 3: Objects as keys

const obj1 = { a: 1 };
const obj2 = { b: 2 };
const container = {};
 
container[obj1] = "first";
container[obj2] = "second";
 
console.log(Object.keys(container));
console.log(container[obj1]);
Answer `["[object Object]"]` and `"second"` — both objects are converted to the same string `"[object Object]"`, second value overwrites the first.

Problem 4: Key ordering

const obj = {
  "2": "two",
  "10": "ten",
  "1": "one",
  "b": "bee",
  "a": "ay"
};
 
console.log(Object.keys(obj));
Answer `["1", "2", "10", "b", "a"]` — numeric keys are sorted in ascending order, string keys follow insertion order.

Problem 5: Function values

const obj = {
  method1: function() { return "method1"; },
  method2() { return "method2"; },
  method3: () => "method3"
};
 
console.log(typeof obj.method1);
console.log(obj.method2());
console.log(obj.method3.name);
Answer `"function"`, `"method2"`, `"method3"` — all values are functions, methods are called normally, arrow functions have names.

Problem 6: Dynamic keys

const prefix = "data";
const keys = ["name", "age"];
 
const obj = {};
keys.forEach((key, index) => {
  obj[`${prefix}_${key}`] = `value_${index}`;
});
 
console.log(Object.keys(obj));
console.log(obj.data_name);
Answer `["data_name", "data_age"]` and `"value_0"` — keys are dynamically created with prefix, access by name works.

Practical tips

1. Choosing between Object and Map

// ✅ Use Object for configurations and records
const userConfig = {
  theme: "dark",
  language: "en", 
  notifications: true
};
 
// ✅ Use Map for dynamic collections
const userSessions = new Map();
userSessions.set(userId1, { loginTime: Date.now() });
userSessions.set(userId2, { loginTime: Date.now() - 1000 });

2. Working with Symbol keys

// ✅ Symbol for metadata and private properties
const META_INFO = Symbol('metaInfo');
 
class Component {
  constructor(props) {
    Object.assign(this, props);
    this[META_INFO] = {
      created: Date.now(),
      version: "1.0.0"
    };
  }
  
  getMetaInfo() {
    return this[META_INFO];
  }
}

3. Safe key creation

// ✅ Key validation
function createSafeObject(entries) {
  const obj = {};
  
  entries.forEach(([key, value]) => {
    // Ensure key is a string
    const safeKey = String(key);
    if (safeKey && safeKey !== "undefined" && safeKey !== "null") {
      obj[safeKey] = value;
    }
  });
  
  return obj;
}
 
const safe = createSafeObject([
  ["name", "John"],
  [null, "bad key"], // Will be skipped
  ["age", 30]
]);

Summary

Object keys:

  • Strings and Symbol are the only true key types
  • Numbers, booleans, null, undefined are automatically converted to strings
  • Objects are converted via toString() (usually not needed)
  • Symbol doesn’t convert, remains unique

Object values:

  • Any data types without limitations
  • Primitives, objects, functions — everything can be stored
  • Reference types maintain references to objects

Practical conclusions:

  • For simple data use Object
  • For complex keys use Map
  • Symbol for private properties and metadata
  • Remember type conversion of keys

Understanding object keys and values is the foundation of effective data handling in JavaScript!


Want more interview preparation articles? Subscribe to EasyAdvice, bookmark the site and improve yourself every day 💪