Create an Empty Object in JavaScript with {} or New Object()

Create an empty object in JavaScript with {} or new Object()?

Objects

There is no benefit to using new Object(), whereas {} can make your code more compact, and more readable.

For defining empty objects they're technically the same. The {} syntax is shorter, neater (less Java-ish), and allows you to instantly populate the object inline - like so:

var myObject = {
title: 'Frog',
url: '/img/picture.jpg',
width: 300,
height: 200
};

Arrays

For arrays, there's similarly almost no benefit to ever using new Array() over [] — with one minor exception:

var emptyArray = new Array(100);

creates a 100 item long array with all slots containing undefined, which may be nice/useful in certain situations (such as (new Array(9)).join('Na-Na ') + 'Batman!').

My recommendation

  1. Never use new Object(); — it's clunkier than {} and looks silly.
  2. Always use [] — except when you need to quickly create an "empty" array with a predefined length.

Creating a new empty object in JavaScript

The object referred to by Bar is shared between each Foo instance.

I don't really see the point of putting the logic into two objects, you can do this with just one constructor function:

function Foo() {
this.__words = {};
}

Foo.prototype.addWord = function(word, amount) {
this.__words[word] = amount;
}

var foo = new Foo();
foo.addWord("hello",7);

var bar = new Foo();
bar.addWord("world",9);

If you really have to separate the functionality, then make Bar a constructor function as well and create a new instance inside the Foo constructor method:

function Foo() {
this.bar = new Bar();
}

function Bar() {
this.__words = {};
}

Bar.prototype.addWord = function(word, amount) {
this.__words[word] = amount;
}

Create an empty object/array, based on an existing object/array

You can use constructor property of thing. And don't use new as variable name.

const transf = (thing) => {
const newelm = new thing.constructor()
}

Demo:

const transf = (thing) => {  return new thing.constructor()}
console.log(transf(['arra']))console.log(transf({key:'value'}))

Why Object.assign({}, ...) with an empty object literal when other objects are also passed in?

When you use Object.assign, the first object you give it will have all the rest of the objects merged into it. That is to say, the first object will be mutated.

If you want to avoid mutating the objects you're merging, it's helpful to pass in the empty object as the first parameter to prevent any of the component objects from changing.

Here's an example demonstrating the difference:

const obj1 = {  foo: "bar"}
const obj2 = { key: "value"}
// Here, obj1 is the same after the Object.assign callconsole.log(Object.assign({}, obj1, obj2));console.log(obj1)console.log(obj2)
console.log("\n\n")
// Note that after this call, obj1 holds both keys. So this will mutate it:console.log(Object.assign(obj1, obj2));console.log(obj1) // This is different nowconsole.log(obj2)

How to create an empty object which has defined value type

You can use an empty object literal and a type assertion to tell the compiler what the expected type of the property will be:

let rockHardObs = {
'Lady': { } as { [key: string]: Gaga }
}

TypeScript empty object for a typed variable

Caveats

Here are two worthy caveats from the comments.

Either you want user to be of type User | {} or Partial<User>, or you need to redefine the User type to allow an empty object. Right now, the compiler is correctly telling you that user is not a User. – jcalz

I don't think this should be considered a proper answer because it creates an inconsistent instance of the type, undermining the whole purpose of TypeScript. In this example, the property Username is left undefined, while the type annotation is saying it can't be undefined. – Ian Liu Rodrigues

Answer

One of the design goals of TypeScript is to "strike a balance between correctness and productivity." If it will be productive for you to do this, use Type Assertions to create empty objects for typed variables.

type User = {
Username: string;
Email: string;
}

const user01 = {} as User;
const user02 = <User>{};

user01.Email = "foo@bar.com";

Here is a working example for you.

Here are type assertions working with suggestion.

Create an empty object at deep path with lodash

There's a _.deepDefault method in an extra lodash-deep library that checks if the value at the propertyPath resolves to undefined, and sets it to defaultValue if this is the case:

var descendant = _.deepDefault(object, 'some.deep.path', {});

That library is not updated anymore because Lodash now supports most of the functionality natively so here's an implementation as a lodash mixin function:

function getOrSetDefault(object, path, defaultValue) {
const descendant = _.get(object, path);
if (descendant === undefined) {
_.set(object, path, defaultValue);
}
return descendant;
}

_.mixin({ getOrSetDefault });

const a = _.getOrSetDefault(object, 'some.deep.path', 42);
const b = _.getOrSetDefault(object, 'some.other.deep.path', {});
b.c = 42;

With the new optional chaining operator and a logical nullish assignment there would be no need to use lodash for this particular case (if it is acceptable to populate/define some.deep.path with a default value), e.g.:

some?.deep?.path ??= {}
const { foo } = some.deep.path

Unfortunately optional chaining assignments are not available yet.
See https://stackoverflow.com/a/58882121/1949503

There would be just one drawback in that there'll be a need to repeat property accessors (some.deep.path) to retrieve the value. However in this case we will have autocompletion using Typescript/JSDoc unlike in lodash funcions' path argument (either string or array)

If there's only a need to get value at path the vanilla try/catch could be sufficient:

let foo: Foo;
try {
foo = some.deep.path.foo
} catch {}


Related Topics



Leave a reply



Submit