Categories
JavaScript JavaScript Basics

Using JavaScript’s Object Constructor — Part 2

Spread the love

In JavaScript, the object constructor lets us create object wrapper with the given values. It will create an empty object if null or undefined is passed into the object constructor. If the value passed into the constructor is an object already, then it will return the object.

The object constructor has two properties. It has a length property that is always 1, and like all other objects, the object constructor has a prototype to get all the property additions to the type object.

Continuing from Part 1, the object constructor has many useful methods that can be used without constructing a new object.


Object.fromEntries()

The Object.fromEntries() method accepts an array with arrays of key-value pairs with the key as the first element and the value of the corresponding key as the second element. We can also pass in other iterables with the same kind of arrays into the method.

For example, we can write the following code to pass in an array of key-value pairs to create an object:

const entries = [  
  [  
    ['a', 1],  
    ['b', 2]  
  ]  
];

const obj = Object.fromEntries(entries);
console.log(obj);

The resulting object obj should be {a: 1, b: 2} as we can see from the console.log output when the code above is run. We can pass in other iterables, such as maps:

const entries = new Map([  
  ['a', 1],  
  ['b', 2]  
]);

const obj = Object.fromEntries(entries);
console.log(obj);

We should see the same thing logged. Also, we can convert arrays to objects with the following code:

const arr = [1,2,3];  
const entries = arr.map((value, index) => [index, value]);
const obj = Object.fromEntries(entries);
console.log(obj);

When the code above is run, we get {0: 1, 1: 2, 2: 3} since we mapped the index of each array entry to the key and the value of each array entry to the value.


Object.getOwnPropertyDescriptor()

The Object.getOwnPropertyDescriptor() method gets the property descriptor of a property in the object and returns it. As the name suggests, it only gets the property descriptor of the object that’s in the object itself and not up the prototype chain.

A property descriptor is an object with the property names as keys and the properties writable, configurable, enumerable, and value as properties of the property name keys.

writable means that the property’s value can be changed. configurable means the property descriptor may be changed and if the property can be deleted from the object.

The enumerable property means that the property shows up during enumeration of the properties with the for...in loop and value is the value of the property.

For example, if we log a property descriptor of an object with:

const obj = {  
  a: 1  
}const descriptor = Object.getOwnPropertyDescriptor(obj, 'a');  
console.log(descriptor);

We get {value: 1, writable: true, enumerable: true, configurable: true} . The value is the value of the property and the rest of the properties are the property descriptor’s properties. If we have property getters and setters, they are also returned with the method call:

let obj = {};  
let value;  
Object.defineProperty(obj, 'a', {  
  get() {  
    return value;  
  },  
  set(a) {  
    value = a;  
  }  
});  
  
const descriptor = Object.getOwnPropertyDescriptor(obj, 'a');  
console.log(descriptor);

When the code above is run, we get the get and set functions back in the descriptor object.


Object.getOwnPropertyDescriptors()

While the Object.getOwnPropertyDescriptor() gets the property descriptor for a single object, the Object.getOwnPropertyDescriptors() gets all the property descriptors of an object in one object—once again without the properties that are inherited by this object up the prototype chain, with the property names as the keys and the property descriptor of the corresponding property name key as the value.

For example, if we have

const obj = {  
  a: 1,  
  b: 2  
}  
const descriptors = Object.getOwnPropertyDescriptors(obj);  
console.log(descriptors);

then we get

{  
  "a": {  
    "value": 1,  
    "writable": true,  
    "enumerable": true,  
    "configurable": true  
  },  
  "b": {  
    "value": 2,  
    "writable": true,  
    "enumerable": true,  
    "configurable": true  
  }  
}

We get all the values and the property descriptor attributes of each property. Like with Object.getOwnPropertyDescriptor(), this method has the same definitions for the property descriptors.

A property descriptor is an object with the property names as keys and the properties writable, configurable, enumerable, and value as properties of the property name keys.

The writable means that the property’s value can be changed. configurable means the property descriptor may be changed and if the property can be deleted from the object.

The enumerable property means that the property shows up during enumeration of the properties with the for...in loop, and value is the value of the property.


Object.getOwnPropertyNames()

The Object.getOwnPropertyNames() method returns an array of property names that are defined in the object itself and not in any object up the prototype chain. Non-enumerable properties are also returned except for those that are symbols. For example, if we have:

let obj = {  
  a: 1,  
  b: 2  
}

Object.defineProperty(obj, 'c', {  
  "value": 2,  
  "writable": true,  
  "enumerable": false,  
  "configurable": true  
})

const names = Object.getOwnPropertyNames(obj);  
console.log(names);

If we run the code above, we get [“a”, “b”, “c”] returned since all properties defined except ones identified with Symbols are returned. If we have Symbols in our object, we won’t see it in the returned array. For example, if we have

let obj = {  
  a: 1,  
  b: 2,  
  [Symbol('foo')]: 3  
}  
Object.defineProperty(obj, 'c', {  
  "value": 4,  
  "writable": true,  
  "enumerable": false,  
  "configurable": true  
})  
const names = Object.getOwnPropertyNames(obj);  
console.log(names);

we still see [“a”, “b”, “c”] if we run the code above since symbols aren’t included in the array. We have the Object.getOwnPropertySymbols() to get properties that are identified with symbols.


Object.getOwnPropertySymbols()

The Object.getOwnPropertySymbols() returns an array of symbols that are used as identifiers in the properties of an object.

It only gets the property identifiers that are named with symbols and nothing else.

Also, it doesn’t traverse up to the prototype chain to get properties of objects up the prototype chain. For example, if we have the following code:

let obj = {  
  a: 1,  
  b: 2,  
  [Symbol('foo')]: 3  
}  
Object.defineProperty(obj, 'c', {  
  "value": 4,  
  "writable": true,  
  "enumerable": false,  
  "configurable": true  
})  
const symbols = Object.getOwnPropertySymbols(obj);  
console.log(symbols);

we get [Symbol(foo)] logged as we expected.


Object.getPrototypeOf()

The Object.getPrototypeOf() method gets the prototype of an object, which is the same as the [[Prototype]] property of the specified object. For example, if we have

const prototype1 = {};  
const obj = Object.create(prototype1);  
console.log(Object.getPrototypeOf(obj) === prototype1);

the console.log will output true since the first argument of Object.create is the prototype object for the object that it returns; likewise, if we use Object.setPrototypeOf() method to set the prototype of an existing object.

const prototype2 = {};  
let obj2 = {};  
Object.setPrototypeOf(obj2, prototype2);  
console.log(Object.getPrototypeOf(obj2) === prototype2);

The console.log will also output true since set the prototype of obj2 explicitly.


Object.is()

The Object.is() method compares whether two objects passed in its argument are the same value. Two values are the same if they’re:

  • both undefined
  • both null
  • both true or both false
  • both strings with the same length and same characters in the same order
  • both objects having the same references
  • both numbers and both +0 , or both -0 or both NaN or both non-zero and both not NaN and they both have the same value

It doesn’t convert types like the == operator to compare objects and don’t convert truthy or falsy values to booleans. Also, it’s not the same as comparing objects with the === operator because with the === operator, -0 and +0 are equal and NaN is not the same as itself.

For example, we can make the following comparisons:

Object.is('a', 'a');             // true  
Object.is(document, document);   // true  
  
Object.is('a', 'b');             // false  
Object.is([], []);               // false  
  
const obj = { a: 1 };  
const obj2 = { a: 1 };  
Object.is(obj, obj);             // true  
Object.is(obj, obj2);            // false  
  
Object.is(null, null);           // true  
  
Object.is(0, -0);                // false  
Object.is(-0, -0);               // true  
Object.is(NaN, 0/0);             // true

As we can see, only object references and values are compared. The object’s content isn’t compared, so even if two objects have the same content, they’re still considered different since their references in memory are different, as they’re defined by two different variables.


Object.isExtensible()

The Object.isExtensible() method checks whether an object’s property is extensible. That is if an object can have new properties added to it. For example, if we have:

const obj = {};  
const obj2 = {};console.log(Object.isExtensible(obj));Object.preventExtensions(obj2);console.log(Object.isExtensible(obj2));

Then console.log(Object.isExtensible(obj)); will log true since we didn’t explicitly prevent adding new properties to obj . However, console.log(Object.isExtensible(obj2)); will log false since we called Object.preventExtensions(obj2); to prevent new properties from being added to obj2 .

If we run the following code, we also get false logged in both console.log statements because we explicitly prevented the objects obj and obj2 from having new properties added with the Object.freeze() and Object.seal() methods respectively:

const obj = {};  
const obj2 = {};  
Object.freeze(obj);  
console.log(Object.isExtensible(obj));Object.seal(obj2);  
console.log(Object.isExtensible(obj2));

Object.isFrozen()

The Object.isFrozen() method determines if an object is frozen. Frozen means that all properties’ values in an object can’t be changed. Also, new properties can’t be added to it, and existing property descriptors for the frozen object can’t be changed. The object is frozen in place. This method doesn’t return a new frozen object. Instead, it returns the original object before it’s frozen. The frozen object’s prototype also can’t be changed. For example, if we have:

const obj = {  
  a: 1  
};console.log(Object.isFrozen(obj));

We get false from the console.log statement because we didn’t explicitly freeze the object by calling Object.freeze(obj). On the other hand, we have frozen the object, then Object.isFrozen() will return true. For example:

const obj = {  
  a: 1  
};Object.freeze(obj);  
console.log(Object.isFrozen(obj));

Then we get true from the console.log statement because we froze the object by calling Object.freeze(obj). If primitive values are passed in, Object.isFrozen() will return true since they’re immutable. For example, if we have:

console.log(Object.isFrozen(1));  
console.log(Object.isFrozen('string'));  
console.log(Object.isFrozen(null));  
console.log(Object.isFrozen(undefined));  
console.log(Object.isFrozen(NaN));  
console.log(Object.isFrozen(true));  
console.log(Object.isFrozen(Symbol('a')));

Then all the console.log statement will be true since they’re all immutable.

The Object constructor has many more methods for constructing objects from an array of an array with key and value of properties and also methods to get property descriptors from objects, property names, property symbols, gets the keys of an object and prevent properties from being added or deleted or modify their property descriptors.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *