Collection Reference Types

Javascripts collection objects types are custom objects, arrays, typed arrays, maps an sets all are which are used in other programming languages however Javascript has implemented with differences.

Object Type

I have using objects in previous sections, now lets go a little deeper, as you already know object can store data and functions that can manipulate that data, you can create object in two ways using the new operator or using a object literal notation. Throughout the various sections you will see numerous examples using the Object type.

creating object using new
let person = new Object();
person.name = "Paul";
person.age = 21;
creating object using object literal
let person = {
    name: "Paul",
    age: 21
    5: true                     // you can also use numbers as property name
};
------------------------------------------------------------------------------------

let person = {};                // you can create a empty object and add it to later

function test(person) {         // remember objects are passed by reference

    person.name = "Paul";
    person.age = 21;
}
accessing object
console.log(person["name"]);         // "Paul"
console.log(person.name);            // "Paul"
changing/adding property values
person["name"] = "Will"
person.name = "Will"

let personProperty = "name"
person[personProperty] = "Will"                // you can use a variable to change a property name

person.createNewProperty = "Comedy"            // add an additional property

Array Type

Arrays are used in nearly all programming languages, they are the most commonly used data store, they are simply to create and use and hence why they are popular. Arrays in Javascript are order and they can hold any types of data, and you can mix and match as well, they are not statical typed as in other programming languages, they are dynamic typed. Arrays will grow and shrink automatically as data is added or subtrcted from them, also arrays in Javascript start at 0, the first index is 0.

Creating arrays
let persons = new Array();
let persons = new Array("Paul", "Will", "Moore", "Graham");

let persons = new Array(20);                // create array length of 20, could increase performance presetting array size
Creating arrays using literal
let persons = [];
let persons = ["Paul", "Will", "Moore", "Graham"];
let numbers = [1, 2, 3, 4, 5];
Creating arrays with holes
const options = [1,,,,5];
// false, true, true, true, false
for (const option of options) {
    console.log(option === undefined);
}
console.log(options.length);                        // results in 5
Creating arrays using from() method
Array.from("Paul")); // ["P", "a", "u", "l"]
----------------------------------------------------------------

const m = new Map().set(1, 2).set(3, 4);
const s = new Set().add(1).add(2).add(3).add(4);

// Array.from() performs a shallow copy of an existing array
let nums = Array.from(m);         // [[1, 2], [3, 4]]
let nums = Array.from(s);         // [1, 2, 3, 4]

Note: there are other ways to copy arrays
Accessing arrays
let persons = ["Paul", "Will", "Moore", "Graham"];
console.log(persons[0]);                // Paul
console.log[persons.length - 1]         // Graham
Changing/adding array
let persons = ["Paul", "Will", "Moore", "Graham"];
persons[0] = "Arthur"                   // change an existing element
persons[4] = "Norman"                   // add a new element in position 3 (remeber srats at 0)
filling arrays
let binaryArray = [0, 0, 0, 0, 0];
binaryArray.fill(1);                     // fill array with 1's            
binaryArray.fill(0);                     // fill array with 0's (reset it)
binaryArray.fill(1, 0, 2)                // fill elements >= 0 and < 2 with 1's

let ints = [0, 1, 2, 3, 4];
ints.copyWithin(5);                      // copy elements 0 to 5 to end of array
alert(ints);                             // [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]

There are many other methods you can use with arrays like conversion, stack, queue, reordering, manipulating, iterative, search, reduction and location methods.

Typed Arrays

A Typed array refers to a colelction of specialized arrays that contain numeric types. The ArrayBuffer is a block of memory which is the fundamental unit referred to by all typed arrays and views. I am going to cover briefly cover each one.

Typed arrays are array-like objects that provide a mechanism for reading and writing raw binary data in memory buffers. JavaScript engines perform optimizations so that these arrays are fast. However, as web applications become more and more powerful, adding features such as audio and video manipulation, access to raw data using WebSockets, and so forth, it has become clear that there are times when it would be helpful for JavaScript code to be able to quickly and easily manipulate raw binary data.

ArrayBuffer
const buf1 = new ArrayBuffer(16);
const buf2 = buf1.slice(4, 12);
alert(buf2.byteLength);                     // 8

Note: a BufferArray cannot not be resized once created.

You can can only access a BufferArray via a view, ther are a number of different views which I will cover now

Data views allows you to read/write to a BufferArray, it is design for file I/O and network I/O, this view is not iterable.

Data View
const buf = new ArrayBuffer(16);

// DataView default to use the entire ArrayBuffer
const fullDataView = new DataView(buf);
fullDataView.byteOffset;                         // 0
fullDataView.byteLength;                         // 16
fullDataView.buffer === buf;                     // true

// There are a number of element types that you can use, int8, Uint8, int16, Uint16, int32, Uint32, Float32, Float64
// Allocate two bytes of memory and declare a DataView

const buf = new ArrayBuffer(2);
const view = new DataView(buf);
// Demonstrate that the entire buffer is indeed all zeroes
// Check the first and second byte
view.getInt8(0);                                 // 0
view.getInt8(1);                                 // 0
// Check the entire buffer
view.getInt16(0);                                // 0
// Set the entire buffer to ones
// 255 in binary is 11111111 (2^8 – 1)
view.setUint8(0, 255);

Typed Arrays is another form of a BufferArray view, this is different to data views but it enforces a single elementtype and obeys the system's native endianness and thus it has greater API and better performance.

Typed Array
// There are a number of element types that you can use, int8, Uint8, int16, Uint16, int32, Uint32, Float32, Float64
            
// Creates a Float32Array from arguments
const floats = Float32Array.of(3.14, 2.718, 1.618);
alert(floats.length); // 3
alert(floats.buffer.byteLength); // 12
alert(floats[2]); // 1.6180000305175781

Map Type

Maps store data in key/value pairs, you could do this with Objects the differences are below:

There are two types of Maps, Map and WeakMap, the WeakMap is how the garbage collector treats its keys, if all references to the key are lost and there are no more references to the value it can be garbage collected. One problem with Map is the possibility of memory leak because the arrays ensure that references to each key and each value are maintained indefinitely, these references prevent the keys from being garbage collected, even if there are no other references to the object.

Weakmaps do not offer iteration and clear because key/value pairs can be destroyed at any time, you also have to have a reference to the key object. The idea with WeakMap is that it preserves the convention that values can only be retrieved with a reference to the key object.

Map examples
const m1 = new Map([
    ["key1", "val1"],
    ["key2", "val2"],
    ["key3", "val3"]
]);

-----------------------------------------------------------------------------------------------------
const persons = new Map();
persons.set("firstName", "Paul").set("lastName", "Valle");
persons.has("firstname");                                               // true
persons.get("firstname");                                               // Paul
persons.size                                                            // 3

-----------------------------------------------------------------------------------------------------
// Maps can use any data type - functions, symbols, objects, etc
const m = new Map();
const functionKey = function() {};
const symbolKey = Symbol();
const objectKey = new Object();

m.set(functionKey, "functionValue");
m.set(symbolKey, "symbolValue");
m.set(objectKey, "objectValue");

m.get(functionKey);                                                     // functionValue
m.get(symbolKey);                                                       // symbolValue
m.get(objectKey);                                                       // objectValue

Note: that Maps retain there order of insertion
WeakMap examples
const wm = new WeakMap([
    ["key1", "val1"],
    ["key2", "val2"],
    ["key3", "val3"]
]);

-----------------------------------------------------------------------------------------------------
// Map and WeakMap use the same creation and methods.
const persons = new WeakMap();
persons.set("firstName", "Paul").set("lastName", "Valle");
persons.has("firstname");                                               // true
persons.get("firstname");                                               // Paul
persons.size                                                            // 3

Set Type

The set type in Javascript is very similar to arrays it offers you to store data that is unique, again we have a WeakSet type and works the same way WeakMap works regarding garbage collection.

Set example
// Sets maintain there order of insertion
let s = new Set();

s.add("Paul");
s.add("Will");
s.add("Moore");
s.add("Graham");
s.add("Paul");

console.log(s)                 // Set { 'Paul', 'Will', 'Moore', 'Graham' }, notice only one Paul

Note: set has methods add, delete, get, has, size,, clear, etc

Iteration and Spread Operators

Iterators and the Spread operators (shallow copying) are useful when using on collection types, they allow for easy interoperability, cloning and modification of colelction types.

Iterator operator example
let iterableThings = [
    Array.of(1, 2),
    typedArr = Int16Array.of(3, 4),
    new Map([[5, 6], [7, 8]]),
    new Set([9, 10])
];

for (const iterableThing of iterableThings) {
    for (const x of iterableThing) {
        console.log(x);
    }
}                                // results in 1, 2, 3, 4, [5, 6], [7, 8], 9, 10
Spread operator example
// Ideal for shallow copying
let arr1 = [1, 2, 3];
let arr2 = [...arr1];
console.log(arr1); // [1, 2, 3]
console.log(arr2); // [1, 2, 3]
console.log(arr1 === arr2); // false