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.