01 - Methods for Creating Objects
Primitive Types can hold only a single value (e.g., numbers, strings, booleans).
Object Types are collections of key-value pairs and can store multiple values. Objects are JavaScript’s most fundamental data type and play a crucial role in the JavaScript language.
They are composite values that aggregate multiple values (primitive values or other objects) and allow you to store and retrieve those values by name.
An object is an unordered collection of properties, each of which has a name and a value. Property names are usually strings (although they can also be Symbols), so you can think of objects as mapping strings to values.
An object is more than just a simple string-to-value map. In addition to maintaining its own set of properties, a JavaScript object also inherits the properties of another object, known as its “prototype.” The methods of an object are typically inherited properties, and this concept of “prototypal inheritance” is a key feature of JavaScript.
What is an Object?
Any value in JavaScript that is not a string, a number, a Symbol, or a boolean (true
, false
), null
, or undefined
is an object. While strings, numbers, and booleans are not objects, they can behave like immutable objects.
Some of the most common operations with objects are: Creating objects, Setting, querying, deleting, testing, and enumerating their properties.
Object Properties
Object property has a name and a value.
- A property name may be any string (including an empty string or any Symbol), but no object may have two properties with the same name.
- The value may be any JavaScript value or it may be a getter or setter function (or both).
In addition to its name and value, each property has three attributes:
- Writable: Specifies whether the value of the property can be set.
- Enumerable: Specifies whether the property name is returned in a
for/in
loop. - Configurable: Specifies whether the property can be deleted and whether its attributes can be altered.
By default, all properties of the objects you create are writable, enumerable, and configurable but, Many of JavaScript’s built-in objects have properties that are read-only, non-enumerable, or non-configurable.
Creating Objects
Objects can be created in 3 ways, using object literals, the new
keyword, or the Object.create()
function.
1. Object Literals
The easiest way to create an object is using an object literal. In its simplest form, an object literal is a comma-separated list of colon-separated name:value
pairs enclosed in curly braces {}
.
let user = { key: value };
A property name is either a JavaScript identifier or a string literal (including the empty string). A property value can be any JavaScript expression, and its result (whether a primitive value or an object) becomes the property value.
An object literal is shorthand for creating objects by defining key-value pairs inside {}
. Each property has a key or name before the colon (:
) and is separated by a comma.
let empty = {}; // An object with no properties
let point = { x: 0, y: 0 }; // Two numeric properties
let p2 = { x: point.x, y: point.y + 1 }; // More complex values
Example with a more complex object:
let book = {
"main title": "JavaScript", // These property names include spaces
"sub-title": "The Definitive Guide", // and hyphens, so use string literals.
for: "all audiences", // 'for' is reserved, but no quotes needed
author: {
firstname: "David",
surname: "Flanagan"
}
};
Example of interacting with object properties:
let user = {
name: "John",
age: 30,
"likes birds": true, // Property name with spaces must be in quotes
};
alert(user.name); // "John"
user.isAdmin = true; // Assigning a new property
delete user.age; // Deletes the 'age' property
Note: Property names can be any string, number, or symbol, including reserved words or multi-word names. Properties with invalid binding names or multi-word names need to be quoted (e.g., "touch wood": "touched"
).
2. Creating Objects with new
The new operator creates and initializes a new object. The new keyword must be followed by a function invocation. A function used in this way is called a constructor and serves to initialize a newly created object. JavaScript includes constructors for its built-in types. For example:
// Create an empty object: same as {}.
let o = new Object();
// Create an empty array: same as [].
let a = new Array();
// Create a Date object representing the current time
let d = new Date();
// Create a Map object for key/value mapping
let r = new Map();
In addition to these built-in constructors, it is common to define your own constructor functions to initialize newly created objects which is covered later.
Prototypes in JavaScript
Almost every JavaScript object has another JavaScript object associated with it, known as its prototype. The first object inherits properties from its prototype.
- The object created by
new Object()
inherits fromObject.prototype
. - Similarly, the object created by
{}
also inherits fromObject.prototype
. - The object created by
new Array()
usesArray.prototype
as its prototype. - The object created by
new Date()
usesDate.prototype
as its prototype.
This concept can be confusing when first learning JavaScript. Remember: almost all objects have a prototype, but only a relatively small number of objects have a prototype property. These objects, which contain the prototype
property, define the prototypes for other objects.
3. Object.create()
Object.create()
is the third way to create an object in JavaScript. It creates a new object, using the first argument as the prototype of that object.
let o1 = Object.create({ x: 1, y: 2 }); // o1 inherits properties x and y
console.log(o1.x + o1.y); // 3
Creating an Ordinary Empty Object
If you want to create an empty object like the one returned by {}
or new Object()
, pass Object.prototype
as the argument:
let o3 = Object.create(Object.prototype);
// o3 is like {} or new Object()
Creating an Object Without a Prototype: You can also pass null
to create a new object that does not inherit from anything, not even basic methods like toString()
:
let o2 = Object.create(null);
// o2 inherits no properties or methods
Object.create()
can take an optional second argument that specifies the properties of the new object. This is an advanced feature that we will cover later.
Use Case: Guarding Against Unintended Modifications
One common use for Object.create()
is when you want to protect an object from unintended modifications by a library function that you don’t control. Instead of passing the object directly to the function, you can pass an object that inherits from it. This way, if the function reads properties of the object, it will see the inherited values. If it sets properties, however, those writes will not affect the original object.
let o = { x: "don't change this value" };
library.function(Object.create(o)); // Guard against accidental modifications
In this case, the library.function
can safely interact with the object, but any changes to properties will not affect the original o
object.
Extended Object Literal Syntax
Recent versions of JavaScript have extended object literal syntax in several useful ways.
1. Shorthand Properties
If you have values stored in variables and want to create an object with properties named after those variables, you can use shorthand syntax introduced in ES6:
let x = 1, y = 2;
let o = { x, y };
o.x + o.y // => 3
Without shorthand, you would have to write repeatedly:
let x = 1, y = 2;
let o = {
x: x,
y: y
};
function makeUser(name, age) {
return {
name, // shorthand for name: name
age, // shorthand for age: age
};
}
let user = makeUser("John", 30);
alert(user.name); // "John"
2. Computed Property Names
Sometimes you need to create an object with a specific property, but the name of that property is dynamic (not a constant at compile-time). Instead of manually adding properties after object creation, ES6 allows you to use computed property names:
const PROPERTY_NAME = "p1";
function computePropertyName() { return "p" + 2; }
let o = {};
o[PROPERTY_NAME] = 1;
o[computePropertyName()] = 2;
With ES6, you can directly use computed properties in the object literal syntax:
const PROPERTY_NAME = "p1";
function computePropertyName() { return "p" + 2; }
let p = {
[PROPERTY_NAME]: 1,
[computePropertyName()]: 2
};
console.log(p.p1 + p.p2); // => 3
In this syntax, the square brackets indicate an arbitrary JavaScript expression, which will be evaluated, and the resulting value (converted to a string if necessary) will be used as the property name.
Using square brackets []
inside object literals to dynamically set property names. This feature is known as computed properties.
let fruit = "apple";
let bag = {
[fruit + 'Computers']: 5 // property name is "appleComputers"
};
console.log(bag.appleComputers); // 5
Dynamically Setting Property Names
let fruit = prompt("Which fruit to buy?", "apple"); // User input with default value "apple"
let bag = {
[fruit]: 5,
// Property name istaken from `fruit` variable
};
alert(bag.apple);
// If the user chooses "apple", this alerts "5"
// { apple: 5 }
This approach works the same as the following code:
let fruit = prompt("Which fruit to buy?", "apple");
let bag = {};
bag[fruit] = 5; // Property name taken from `fruit` variable
Both methods allow you to dynamically create property names in an object based on variables or expressions.