Categories
JavaScript

Using JavaScript’s Object Constructor — Part 3

Spread the love

In JavaScript, the Object constructor lets us create an 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.

In this article, we look at how to prevent changes and getting keys and values.


Object.isSealed()

The Object.isSealed() method is used to check whether an object is sealed.

Sealing an object means that we prevent new properties from being added to an object and mark all existing ones as non-configurable, which means that the property descriptor of the property can’t change and the property can’t be deleted.

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 whether 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.

It returns true is the object is sealed, otherwise returns false. For example, we can use the function as follows:

let obj = {};  
const objSealed = Object.isSealed(obj);  
console.log(objSealed);

This is the simplest case where the object has not been explicitly sealed or has the property descriptors modified. The console.log statement above would return false since the object isn’t sealed.

let obj = {};  
Object.preventExtensions(obj);  
const objSealed = Object.isSealed(obj);  
console.log(objSealed);

If we call the Object.preventExtensions() method to prevent properties from being added, then objSealed in the code above would return true since we prevented properties from being added with the Object.preventExtensions() method and there’re no existing properties in the object. This only applies to empty objects.

If we set a property’s descriptor with the configuration property to false and we call Object.preventExtensions() on the object, then the Object.isSealed() will return true since we prevented an object’s property’s property descriptor from being modified or deleted.

For example, if we have:

If we call the Object.seal() method on an object, then it does everything to seal the object, which includes preventing properties from being added, preventing existing properties’ property descriptors from being modified, and also preventing object’s properties from being deleted.

For example, if we have:

let sealedObj = { a: 1 };  
Object.seal(sealedObj);  
console.log(Object.isSealed(sealedObj));

The console.log above will log true since we called Object.seal() on the object.


Object.keys()

The Object.keys() method returns an array of an object’s property names in strings that are set to be enumerable. They are returned in the same order as a normal loop.

If an array is passed in as an argument, then we have the indexes of the array returned. For example, if we have:

const obj = {  
  a: 1,  
  b: 2,  
  c: 3  
};  
console.log(Object.keys(obj));

Then we get [“a”, “b”, “c”] when we run console.log since we have those property names in the object obj.

We can also pass arrays into the method. For example, we can write:

const arr = [1, 2, 3];  
console.log(Object.keys(arr));

Then we get [“0”, “1”, “2”] when we run console.log since we have those properties as indexes in the arr array. If we have an array-like object that has all numerical keys, then we get the keys returned in order.

For example:

const obj = {  
  2: 1,  
  3: 2,  
  1: 3  
};  
console.log(Object.keys(obj));

Then we get [“1”, “2”, “3”] when we run console.log since we have numerical keys and the Object.keys() method will return the numerical keys in ascending order.

If we have a mix of numerical and non-numerical keys, then the numerical keys will be returned in ascending order before the rest is returned. For example, if we have:

const obj = {  
  a: 1,  
  3: 2,  
  1: 3  
};  
console.log(Object.keys(obj));

Then we get [“1”, “3”, “a”] when we run console.log.

Only names of enumerable properties are returned by Object.keys(). For example, if we have:

Then the console.log will return an empty array since the property a has a property descriptor where enumerable is set to false.


Object.preventExtensions()

The Object.preventExtensions() method prevents new properties from being added to an object. New properties can’t be added after Object.preventExtensions() is called on it.

However, existing properties can still be deleted. An object can’t be made extensible again after it has been made non-extensible. Its return value is the object that has been made no-extensible. For example, if we have:

let obj = {};  
Object.preventExtensions(obj);  
Object.defineProperty(obj, 'a', {})

We will get an error message saying: ‘Cannot define property a, object is not extensible.’

This is what’s expected since we stopped properties from being able to be added to an object with the Object.preventExtensions() method.

If we try to add a property to it with the dot notation, like in the code below:

let obj = {};  
Object.preventExtensions(obj);  
obj.a = 1;  
console.log(obj);

We get an empty object logged since we called Object.preventExtension() on it. If we run the code above in strict mode like in the code below, we will get ‘Cannot define property a, object is not extensible.’:

'use strict';  
let obj = {};  
Object.preventExtensions(obj);  
obj.a = 1;  
console.log(obj);

If we pass in a primitive value to the method, it will be returned as-is as if it is a non-extensible object. For example, if we have:

console.log(Object.preventExtensions(1));

Then we get 1 since it returns primitive values as-is. In ES5, the same code will log a TypeError.


Object.seal()

The Object.seal() method seals an object. Sealing an object means that we prevent new properties from being added to an object and mark all existing ones as non-configurable, which means that the property descriptor of the property can’t change and the property can’t be deleted.

The values of the properties can still be modified unless their property descriptor’s writable property is explicitly set to false. The prototype chain isn’t modified, but the __proto__ property is also sealed.

Before Object.seal() is called on an object, properties can be added, their property descriptors modified, or properties can be deleted at will. For example, we can write:

If we have run console.log on obj, then we see that we get {a: 3} because we modified the value of a and deleted the b property.

By default, JavaScript objects aren’t sealed, so you may change the properties however you like.

Once we call Object.seal() on an object, like in the code below:

We get {a: 3, b: 2} in the console.log output since Object.seal() prevents properties from being deleted, but doesn’t stop the property’s values from being assigned. For example, if we have the following code:

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

Then we get:

In the console.log since the whole purpose of Object.seal() is to set the configurable property of each property descriptor to false.

This means that their property descriptors can no longer be changed and the properties can’t be deleted from the object.


Object.setPrototypeOf()

The Object.setPrototypeOf() method lets us set the prototype of an object. It takes two parameters. The first parameter is the object you want to change the prototype of, and the second parameter is the prototype object that you want to set it to.

This means that we change the object that the object where the Object.setPrototypeOf() is being called on is inheriting from.

The method can’t be called on non-extensible objects, that is, the ones that have Object.isExtensible() returned false. It does nothing if the prototype parameter isn’t an object or it’s null.

For example, if we have a normal object, then we can set the prototype of the object with the Object.setPrototypeOf() method. The object with the prototype set is returned. For example, if we have:

Then we get {a: 3, b: 4} as the value of newObj with its prototype being the proto object. We can also set an object’s prototype to null with this method:

let obj = {  
  a: 3,  
  b: 4  
};  
const newObj = Object.setPrototypeOf(obj, null);  
console.log(newObj);

Then we get {a: 3, b: 4} as the value of newObj with its prototype being null. The method doesn’t work if the object where the prototype is being set is not extensible. For example, if we have:

Then we will get a TypeError because the object is sealed, which means that all properties, including the prototype property, can’t be added.

Likewise, if we freeze an object, which seals an object and also prevents properties’ values from being changed, it will also fail when we call this method. For example, if we have:

Then we will get a TypeError.


Object.values()

The Object.values() method returns an array of objects that are the values of the enumerable top-level properties in an object. They’re returned in the same order as in the for...in loop.

However, Object.values() do not return the values of properties that are up the prototype chain. For example, if we have:

const obj = {  
  a: 1,  
  b: 2,  
  c: 3  
};console.log(Object.values(obj));

Then we get [1, 2, 3] because we have three properties listed in the obj object. If we have an object like array with all numerical keys, then they’re enumerated in ascending order. For example, if we have:

const obj = {  
  6: 1,  
  5: 2,  
  4: 3  
};  
console.log(Object.values(obj));

Then we get [3,2,1] logged because the keys are ordered in ascending order since they’re all numbers. If we have an array, then the array is returned as-is. For example, if we have:

const arr = [1, 2, 3]  
console.log(Object.values(arr));

Then we get [1, 2, 3] logged because we passed in an array to the Object.values() method. If we have values of properties that aren’t enumerable then they won’t be listed. For example, if we have:

Then we get [“a”] logged because we only have the property a being enumerable.


Conclusion

The Object constructor has many more methods for constructing objects from an array with key and value of properties, and also methods to get property descriptors from objects, property names, and property symbols.

It gets the keys of an object and prevents properties from being added or deleted or modifying their property descriptors.

They’re very useful for controlling how properties behave since JavaScript objects are dynamic by default. These methods can prevent accidental changes more easily.

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 *