Objects

What are objects in JavaScript?

In JavaScript objects are collections of properties i.e. key identified values. Values can be all JavaScript primitive and structural types.

Each property in an object is described by its attributes regarding whether a given property can be retrieved, changed, deleted or enumerated on. The attributes can be set using Object.defineProperty().

Properties can be categorised in two categories: 1) data properties, and 2) accessor properties. Accessor properties can be associated with get and/or set functions that are used respectively to retrieve and store values.

String & Symbol Keyed Objects

What is commonly referred to as an object in JavaScript is a string or a symbol keyed object. Such objects are most often created object literal syntax.

const myObj = {
  a: 1,
  b: 2
}
console.log(myObj) // {a: 1, b: 2}
myObj.c = 3
console.log(myObj) // {a: 1, b: 2, c: 3}
myObj.a = 4
console.log(myObj) // {a: 4, b: 2, c: 3}

Mutability of Objects

Objects in JavaScript are mutable. It is possible to change them through adding additional properties and/or changing the existing ones.

Arrays: Integer Keyed Objects

Arrays in JavaScript are special kinds of integer keyed objects inheriting from Array.prototype. Arrays are most commonly declared and defined using the literal syntax [...].

const myArr = ['a', 'b', 'c']
myArr.push('d')
console.log(myArr) // ['a', 'b', 'c', 'd']

myArr[0] // => "a"
myArr[1] // => "b"
myArr[myArr.length - 1] // => "d"

Operations on Arrays

There are many built-in capabilities of arrays inherited from Array.prototype: forEach, push, pop, shift, unshift, splice, slice, join, concat, indexOf, map, reduce, reverse, values, toString, .

Sets & WeakSets: Collections of Unique Values

Set and WeakSet are collection of unique values. The difference between Set and WeakSet is that 1) the Set type object can include both primitives and object references as values and the WeakSet type can include only references to objects, 2) object referenced values in WeakSet type object are held weakly which impacts garbage collection and do not allow for enumerability.

The most notable instance methods of Set and WeakSet are: add, delete, and has.

Maps & WeakMaps: Objects as Keys

The objects of Map and WeakMap types are ordered collections of key-value properties in which objects can be keys (as opposed to string and symbol keyed objects). The difference between Map and WeakMap is that 1) keys in the Map type objects might be primitives and objects and in WeakMap only objects, 2) in object of WeakMap type keys (as well as values) are weakly referenced and therefore are not enumerable.

Map and WeakMap can be used to enhance performance to allow for easier iteration.

The most notable instance methods of Map and WeakMap are: get, set, delete, and has.

Spread: Shallow Cloning & Appending

Spread is syntactically denoted by three dots ... and it allows 1) an iterable object such as an array or a string to be spread (shallowly cloned and appended) a) as a function arguments in argument list where the function expects zero or more arguments, or b) as a part of another iterable object, or 2) (ES2018) an object with enumerable properties to be spread (shallowly cloned and appended) as a part of another object.

function multiply(a, b, c) {
  return a * b * c
}

const numbers = [5,10,15,20]
multiply(...numbers) // => 750
// Compare with Function.prototype.apply().

const newNumbers = [2, 4, 6]
const combinedNumbers = [ 42, ...numbers, ...newNumbers, 43]
combinedNumbers // => [42, 5, 10, 15, 2, 4, 6, 43]
// Compare with Array.prototype.concat().

// ES2018
const anObj = { a: 1 }
const anotherObj = { b: 2 }
const combinedObject = { ...anObj, ...anotherObj, c: 3 }
combinedObject // => {a: 1, b: 2, c:3} // Compare with Object.assign().

Spread syntax can be useful at new operator given that apply can't be used.

Using a spread syntax with object literals shallowly (and not deeply) clones enumerable properties (excluding prototype) of the spread objects. The difference between spread and Object.assign() is that the latter - in addition to cloning - triggers setters and the spread does not.

Not all objects are iterable. As a rule, the spread syntax - with the exclusion of ES2018 spreading properties - can be applied to iterable objects only.

Rest: Variadic Functions

Syntactically rest parameter syntax is denoted - just like the spread syntax - with three dots ... and is a way of creating of variadic functions i.e. functions that accepts indefinite number of arguments as an instances of Array.

function multiply(...numbers) {
  return numbers.reduce((p, c) => p * c)
}

multiply(1, 2, 3, 15, 20) // => 1800

The rest parameter can be used in a given function parameters only once and at the end of the parameter list.

The difference between arguments and the rest parameters is that the arguments 1) is not an array but another kind of object with its own defined properties and, 2) the arguments includes all function arguments and rest parameter only those encompassed by it.

Object Destructuring

The object destructuring assignment in JavaScript is a syntactical way of drawing enumerable properties from objects (including arrays) and assigning them to variables.

let [a, b] = [1,2]
a // => 1
b // => 2
const [c,d] = [3, 4]
const [e, f, ...g] = [1, 2, 3, 4, 5] // Rest syntax
g // => [3, 4, 5]

const { a, b } = { a: 1, b: 2, c: 3 }
const { a, b, ...c } = { a: 1, b: 2, c: 3, d: 4, e: 5 } // ES2018
c // => {c: 3, d: 4, e: 5}

const { a, b, c } = [1, 2]
c // => undefined
const { a } = {}
a // => undefined

It is possible to indicate a default value in the destructuring assignment.

const [a=2, b=1] = [3]
a // => 3
b // => 1

const { a = 10, b = 15 } = { a: 5 }
a // => 5
b // => 15

It is possible to ignore some values during a destructuring assignment.

const [a, , b] = [41, 42, 43]
a // => 41
b // => 43

It is possible to assign new property names during destructuring assignment.

const { a: x, b: y, c: z = 3 } = { a: 1, b: 2 }

It is possible to use assigning new property names and default values at the same time.

It is possible to destructure nested properties.

const { foo: { bar } } = { foo: { bar: 1 } }
bar // => 1

It is possible to use destructuring assignment with function parameters.

function logAAndB({ a, b }) {
  console.log(a)
  console.log(b)
}

logAAndB({ a: 1, b: 2 }) // 1 2

It is possible to assign new property names and use default values during destructuring assignment of a function parameters.