ArganoのWanです。 この記事では、JavaScriptにおけるオブジェクト操作に役立つ組み込みメソッドについて紹介します。
Introduction
In JavaScript, objects are a fundamental structure for managing complex data. Beyond storing key-value pairs, they allow functions to be encapsulated as methods. This post covers the built-in static object methods frequently used to manage and transform object data safely and concisely.
Getting data from Objects
The following object represents a standard data structure used throughout the examples in this post:
const userConfig = {
id: "32975023530592",
username: "wan",
email: "wan@example.org",
role: "admin",
preferences: { theme: "dark", notifications: true },
loginCount: 14,
status: "active"
};
When handling objects, common tasks involve isolating either the keys or the values. Object.keys(), Object.values(), and Object.entries() serve as the standard utilities for these data extraction requirements.
Object.keys()
console.log(Object.keys(userConfig));
// Expected output: Array ["id", "username", "email", "role", "preferences", "loginCount", "status"]
This method extracts the top-level keys and returns them as an array of strings. It is useful for inspecting the schema of an unknown object. It does not recurse into nested structures; only the top-level property names are returned.
Object.values()
console.log(Object.values(userConfig));
// Expected output: Array ["32975023530592", "wan", "wan@example.org", "admin", { theme: "dark", notifications: true }, 14, "active"]
This method extracts the values associated with the top-level keys and returns them in an array, preserving their original data types.
Object.entries()
console.log(Object.entries(userConfig));
/*
Expected output:
[
["id", "32975023530592"],
["username", "wan"],
["email", "wan@example.org"],
["role", "admin"],
["preferences", { theme: "dark", notifications: true }],
["loginCount", 14],
["status", "active"]
]
*/
for (const [key, value] of Object.entries(userConfig)) {
console.log(`User's ${key} is set to: ${value}`)
}
/*
Expected output:
User's id is set to: 32975023530592
User's username is set to: wan
User's email is set to: wan@example.org
User's role is set to: admin
User's preferences is set to: [object Object]
User's loginCount is set to: 14
User's status is set to: active
*/
This method extracts both keys and values simultaneously, returning a two-dimensional array of [key, value] pairs. It acts as the foundational step for loop operations and complex transformations via array methods.
Manipulate Objects with Array Methods
When modifying or filtering object properties in bulk, converting the object into an array allows the direct application of standard array prototype methods like .map() and .filter().
Object.entries() and Object.fromEntries()
console.log(Object.fromEntries(Object.entries(userConfig)));
/*
Expected output:
{
id: "32975023530592",
username: "wan",
email: "wan@example.org",
role: "admin",
preferences: { theme: "dark", notifications: true },
loginCount: 14,
status: "active"
}
*/
Combining Object.entries() with its counterpart, Object.fromEntries(), creates a reliable pipeline: converting an object into an array format for transformation, and restoring it to an object structure afterward.
const array = Object.entries(userConfig);
const filteredArray = array.filter(([key]) => key !== "role");
const object = Object.fromEntries(filteredArray);
console.log(object);
/*
Expected output:
{
id: "32975023530592",
username: "wan",
email: "wan@example.org",
preferences: { theme: "dark", notifications: true },
loginCount: 14,
status: "active"
}
*/
In the example above, specific properties (e.g., role) are omitted using the array .filter() method before the structure is parsed back into an object.
const array = Object.entries(userConfig);
const mapperArray = array.map(([key, value]) => {
if (key === "loginCount") {
return [key, 0];
}
return [key, value];
});
const object = Object.fromEntries(mapperArray);
console.log(object);
/*
Expected output:
{
id: "32975023530592",
username: "wan",
email: "wan@example.org",
role: "admin",
preferences: { theme: "dark", notifications: true },
loginCount: 0,
status: "active"
}
*/
Similarly, the array .map() method allows the targeted modification of specific values based on conditional logic. This immutable transformation approach prevents accidental side effects on the original reference.
Securing Object Structure and Immutability
JavaScript objects are mutable by default. Declaring an object reference with const only protects the reference pointer itself; the underlying properties can still be modified, appended, or deleted.
Unchecked mutations present structural risks, often resulting in runtime errors when functions attempt to resolve properties that have been removed. Native methods allow for explicit structural protection.
Object.seal()
Object.seal() fixes the object structure. Once executed, appending new properties or deleting existing properties is strictly prevented.
const sealedConfig = Object.seal({ ...userConfig });
sealedConfig.twoFactorEnabled = true;
console.log(sealedConfig.twoFactorEnabled);
// Output: undefined
delete sealedConfig.email;
console.log(sealedConfig.email);
// Output: "wan@example.org"
Object.seal() blocks the addition of new properties, which serves as a runtime safeguard against typographical errors. When JavaScript is executed in strict mode ("use strict"), attempting to assign a new property to a sealed object will instantly trigger a runtime TypeError instead of failing silently. By sealing objects, typographical errors are caught the moment the code executes, rather than mutating an unintended property and failing silently. This provides a structural safety net that prevents typos from corrupting data shapes, directly increasing application stability.
"use strict";
const strictSealed = Object.seal({
username: "wan",
email: "wan@example.org"
});
// Here is a typographical example, the property 'username' is being misspelled as 'usernmae'
strictSealed.usernmae = "kin";
// TypeError: Cannot add property usernmae, object is not extensible
While the structural layout is locked, modifying the values of pre-existing properties remains fully permissible. Additionally, structural sealing operates shallowly; nested references (like the preferences object) remain unprotected.
sealedConfig.status = "inactive";
console.log(sealedConfig.status);
// Output: "inactive"
sealedConfig.preferences.theme = "light";
console.log(sealedConfig.preferences.theme);
// Output: "light"
Object.freeze()
Object.freeze() forces an object into a comprehensive read-only state. It stops structural modifications and blocks value assignments across all top-level properties.
const freezedConfig = Object.freeze({ ...userConfig });
freezedConfig.twoFactorEnabled = true;
console.log(freezedConfig.twoFactorEnabled);
// Output: undefined
delete freezedConfig.email;
console.log(freezedConfig.email);
// Output: "wan@example.org"
freezedConfig.status = "inactive";
console.log(freezedConfig.status);
// Output: "active"
Object.freeze() comes in handy when you are dealing with constants, like parameters loaded from an environment config file. These values shouldn’t change, and freezing them gives you an immutable object that guarantees your data stays untouched. Just like with seal, using Object.freeze() in strict mode throws a runtime error if anyone tries to alter a property. This forces you to catch data mishandling early during development rather than letting mutations slip into production.
"use strict";
const strictFreezed = Object.freeze({
username: "wan",
email: "wan@example.org"
});
strictFreezed.username = "kin";
// TypeError: Cannot assign to read only property 'username' of object '#<Object>'
Similar to Object.seal(), freezing is a shallow operation. To secure deep nested immutability, Object.freeze() must be explicitly targeted at child references individually.
freezedConfig.preferences.theme = "light";
console.log(freezedConfig.preferences.theme);
// Output: "light"
Object.freeze(freezedConfig.preferences);
freezedConfig.preferences.theme = "dark";
console.log(freezedConfig.preferences.theme);
// Output: "light"
Replacement in TypeScript
During daily development, I usually use TypeScript but not JavaScript. Because of this, I had never used Object.seal() or Object.freeze() before. The reason behind this is because TypeScript offers better options to deal with the problem they have been trying to tackle. For example, Object.seal() makes sure any typographical mistakes are noticed early. Yet, for TypeScript, once the object is typed, type check will be carried out by the TypeScript engine when editing the code. When there is a typographical error, the code editor will immediately show an error message and a red line under the typographical error. Therefore, without applying Object.seal() to the object, only by typing the object itselves TypeScript provides a spelling check.
For Object.freeze(), its main function is to make objects immutable. Both the properties and the values. Yet, in TypeScript, just like Object.seal(), there is a better way to tackle this problem. During the declaration of objects, by passing Readonly during the type declaration, the property’s value becomes immutable. Which is just what Object.freeze() is doing. Yet, same as Object.freeze(), the immutable lock by Readonly is also shallow and only locks the top layer of properties in the object.
type Config = Readonly< {
username: string;
email: string;
}>
const config: Config = {
username: "wan",
email: "wan@example.org"
};
config.username = "kin";
// Cannot assign to 'username' because it is a read-only property.(2540)
Besides Readonly, there is another method to make object immutable in TypeScript. as const makes objects immutable, including property, key, and even nested structure inside of it. Unlike Readonly and Object.freeze(), it will make the whole object immutable.
type Config = {
username: string;
email: string;
};
const config = {
username: "wan",
email: "wan@example.org"
} as const satisfies Config; // satisfies will ensure the config object matches the type Config
config.username = "kin";
// Cannot assign to 'username' because it is a read-only property.(2540)
TypeScript, a static type language, provides strong type checking during code editing and compiling. There is a better and easier method to deal with the problem Object.seal() and Object.freeze() trying to solve. Because of that, the chances of using these two methods in TypeScript is relatively lower.
Conclusion
This post outlines the native methodologies for extracting data from objects, executing pipeline operations via array conversion, and enforcing structural protection levels.
Processing payload parsing or maintaining reliable component states relies heavily on using these native capabilities correctly. Relying on standard language implementations before reaching for external utility libraries directly minimizes dependency footprints and protects code maintainability across projects.
