Skip to main content

Ways to create an object

In JavaScript an object can be created in at least ten ways, from the {} literal to Object.fromEntries(). The choice depends on whether you need a template with methods, an explicit prototype, or just a copy of existing data.

Theory

TL;DR

  • The object literal {} is the most readable and most common way.
  • new Object() does the same thing but looks dated and is barely used now.
  • A constructor function with new and a class create objects "from a template"; class is syntactic sugar over the function.
  • A factory function simply returns an object, with no new and no prototypal inheritance.
  • Object.create(proto) sets the prototype explicitly.
  • JSON.parse(), Object.assign(), the spread form { ...obj } and Object.fromEntries() build an object from existing data.

Quick example

javascript
const user = { name: 'Oleh', age: 25, isAdmin: false }; // properties can be added and removed dynamically user.city = 'Kyiv'; delete user.isAdmin; console.log(user); // { name: 'Oleh', age: 25, city: 'Kyiv' }

The literal and new Object()

The object literal is the simplest and most widespread way:

javascript
const user = { name: 'Oleh', age: 25, isAdmin: false };

The same result through the constructor:

javascript
const user = new Object(); user.name = 'Oleh'; user.age = 25;

new Object() does exactly what {} does, but takes longer to write and looks old fashioned, so it is hardly used today.

Templates: constructor function and class

Before class existed, templated objects were created with a constructor function:

javascript
function User(name, age) { this.name = name; this.age = age; } const oleh = new User('Oleh', 25); const alice = new User('Alice', 30); console.log(oleh.name); // "Oleh"

When a function is called with new, the engine does the following under the hood:

  1. creates an empty object {};
  2. assigns it to this;
  3. returns that object (unless the function explicitly returns another one).

The ES6 class is the same mechanism with a nicer syntax:

javascript
class User { constructor(name, age) { this.name = name; this.age = age; } sayHi() { console.log(`Hi, I am ${this.name}`); } } const oleh = new User('Oleh', 25); oleh.sayHi(); // "Hi, I am Oleh"

Class methods live on User.prototype, that is, one copy of the method for all instances.

Factory function and Object.create()

Instead of class or new you can simply return an object:

javascript
function createUser(name, age) { return { name, age, sayHi() { console.log(`Hi, ${this.name}`); } }; } const oleh = createUser('Oleh', 25); oleh.sayHi(); // "Hi, Oleh"

A very convenient approach, especially when you need neither prototype nor inheritance. The downside is that every instance gets its own copy of the method.

Object.create() builds a new object with the given prototype:

javascript
const person = { greet() { console.log(`Hi, I am ${this.name}`); } }; const user = Object.create(person); user.name = 'Oleh'; user.greet(); // "Hi, I am Oleh"

It is used when the prototype chain has to be set explicitly. A special case, Object.create(null), gives a "clean" object with no inherited methods at all, which is handy as a dictionary.

Building from existing data

From a JSON string, the typical case for a server response:

javascript
const json = '{"name": "Oleh", "age": 25}'; const user = JSON.parse(json); console.log(user.name); // "Oleh"

It works with plain data types only, methods do not survive a trip through JSON.

Object.assign() creates an object out of other ones by copying their properties:

javascript
const base = { a: 1 }; const extra = { b: 2 }; const result = Object.assign({}, base, extra); console.log(result); // { a: 1, b: 2 }

The spread syntax does the same thing more briefly and is the modern standard for copying and merging:

javascript
const user = { name: 'Oleh', age: 25 }; const copy = { ...user, city: 'Kyiv' }; console.log(copy); // { name: 'Oleh', age: 25, city: 'Kyiv' }

Object.fromEntries() assembles an object from an array of [key, value] pairs:

javascript
const entries = [['name', 'Oleh'], ['age', 25]]; const user = Object.fromEntries(entries); console.log(user); // { name: 'Oleh', age: 25 }

What to choose

WayExampleNotes
Object literal{ name: 'Oleh' }the most common way
new Object()new Object()rarely used
Constructor functionfunction User() { this.name = ... }the old alternative to class
classclass User { ... }the modern OOP approach
Factory functionfunction createUser() { return {...} }no this, it just returns an object
Object.create(proto)Object.create(person)creates an object with a given prototype
JSON.parse()JSON.parse('{"a":1}')creates an object from a string
Object.assign()Object.assign({}, obj1, obj2)copies and merges objects
Spread syntax{ ...obj1, ...obj2 }short copying syntax
Object.fromEntries()Object.fromEntries([['a', 1]])from an array of pairs to an object

In short: the most popular way is {}, for inheritance use Object.create(), for templates use class or a constructor function, and for copying use { ...obj } or Object.assign().

Common mistakes

  • Calling a constructor function without new. In sloppy mode this points at the global object and pollutes it; in strict mode you get a TypeError.
  • Expecting a deep copy from spread or Object.assign(). Both copy shallowly: nested objects stay shared. For a deep copy use structuredClone().
  • Using JSON.parse(JSON.stringify(obj)) as a universal clone. Functions and undefined are lost, a Date turns into a string, and circular references throw.
  • Confusing Object.create(proto) with new. The first only sets the prototype, the second also runs the constructor.
  • Creating methods in a factory function for thousands of objects. Every instance gets its own copy of the function, while a class keeps one on the prototype.
  • Using a plain {} as a dictionary for arbitrary keys. Keys such as __proto__ or toString clash with the prototype; Object.create(null) or a Map is safer.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.