Categories
Modern JavaScript

Best of Modern JavaScript — Typed Array Properties

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at JavaScript typed arrays.

Typed Arrays

Typed arrays are arrays where its elements can only be numbers.

The constructors that can create integer only typed arrays include Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, and Uint32Array .

Floating-point number only arrays include Float32Array and Float64Array .

Typed Arrays vs Normal Arrays

Typed arrays are very similar to normal arrays.

They have a length property and elements can be accessed with the bracket operator with their indexes.

The standard array methods are also available.

All their elements are always of the same type.

Setting elements convert the value to the type allowed.

Typed arrays are always contiguous.

Normal arrays can have holes, but typed arrays can’t.

They’re always initialized with zeroes because they can’t have holes.

For example:

new Array(5)

creates an array with 5 empty slots, but:

new Uint8Array(5)

creates a typed array with 5 zeroes.

A typed array also has an associated buffer.

The elements of a typed array is stored in an associated ArrayByffer that can be accessed with the buffer property.

Typed Arrays are Iterable

Typed arrays are iterable.

It has a Symbol.iterator method to make it an iterable object.

So we can use the for-of loop with them.

For example, we can write:

const arr = Uint8Array.of(1, 2, 3, 4, 5);
for (const byte of arr) {
  console.log(byte);
}

Then we get 1, 2, 3, 4, and 5 logged.

Converting Typed Arrays to and from Normal Arrays

We can convert between typed and normal arrays.

For instance, we can create a typed array from a normal array by writing:

const typedArr = new Uint8Array([1, 2, 3, 4, 5]);

We can convert a typed array to a normal with slice method or the spread operator.

To call slice to convert the typed array to a normal array, we can write:

const typedArr = new Uint8Array([1, 2, 3, 4, 5]);
const arr = Array.prototype.slice.call(typedArr);

We can also use the spread operator by writing:

const typedArr = new Uint8Array([1, 2, 3, 4, 5]);
const arr = [...typedArr];

We can also use the Array.from method to do the same thing.

For example, we can write:

const typedArr = new Uint8Array([1, 2, 3, 4, 5]);
const arr = Array.from(typedArr);

In all 3 examples, we get [1, 2, 3, 4, 5] for arr .

Inheritance Hierarchy of Typed Arrays

Typed array classes all have a common superclass.

The superclass isn’t directly accessible from our JavaScript code.

The prototype property of the typed array constructor holds all the methods of a typed array.

Static Typed Array Methods

Typed array constructors have some static methods.

One of them is the of method.

We can create a typed array from it with the arguments becoming the entries of it.

For example, we can write:

const typedArr = Uint8Array.of(1, 2, 3, 4, 5);

to call of with some numbers which end up in typedArr .

Conclusion

Typed arrays are similar to normal arrays but have many properties that set them apart.

Categories
Modern JavaScript

Best of Modern JavaScript — Typed Array Methods

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at JavaScript typed arrays methods.

Static Methods

The from static method lets us convert an array-like or iterable object into a typed array.

The first argument is the iterable object we want to convert to a typed array.

The 2nd is a callback that has the value of the entry and the index as the parameter of the array to let us return something we want.

The 3rd argument is the value of this we want to have in the callback in the 2nd argument.

The 2nd and 3rd arguments are optional.

For example, we can write:

const typedArr = Uint16Array.from([0, 1, 2]);

We pass in the array value and returns a Uint16Array with the entries from the array.

The callback for mapping the entries let us create a new array that doesn’t overflow rather than have them overflow.

For example, instead of writing:

const arr = Int8Array.of(200, 201, 202).map(x => 2 * x)

And get the Int8Array with values [-112, -110, -108] . We can write:

const arr = Int32Array.from(Int8Array.of(120, 121, 122), x => x * 2)

and get [240, 242, 244] in an Int32Array .

Instance Properties

There are many instance properties included with typed arrays.

The buffer property is a getter than returns the buffer that’s storing the data of the typed array.

The byteLength property is a number that returns the size in bytes of the typed array’s buffer.

byteOffset returns the offset where the typed array starts inside the ArrayByffr.

set copies all elements of an array or typed array into the given typed array.

If it’s a normal array, then all elements are converted to numbers.

If the argument is a typed array, then each element is converted to the type appropriate for the typed array.

subarray returns a new typed array that has the same buffer as the typed array it’s called on.

It takes the beginning index as the first argument. The default value of this is 0.

The end index is its second argument. The default value of this is the length of the array.

The values can be negative.

Array Methods

Array methods like copyWithin , entries , every , fill , filter , find , findIndex , forEach , indexOf , join , keys , lastIndexOf , length , map , reduce , reduceRight , reverse , slice , some , sort , toLocaleString , toString , and values are all available to typed arrays.

They take the same arguments and have the same return values as regular array methods.

Constructor

Typed arrays constructors include Int8Array, Uint8Array, Uint8ClampedArray , Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array.

They can have the signature (buffer, byteOffset=0, length?) , (length) , (typedArray) ,(arrayLikeObject) , or () .

buffer is the buffer of a typed array.

ByteOffset is the offset from index 0.

length is the length of the typed array.

typedArray is another typed array.

arrayLikeObject is an array-like or iterable object.

An array-like object is one with the length property and integer keys.

Conclusion

Typed arrays have many array methods.

The constructor is different from the regular Array constructor.

Categories
Modern JavaScript

Best of Modern JavaScript — Sets and WeakSets

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at sets and WeakSets.

Set API

The Set API has various methods we can use to let us manipulate it.

The constructor lets us pass in an iterable object and create a set from it.

For instance, we can write:

const set = new Set([1, 2, 3]);

to create a set from an array.

The Set.prototype.add method takes a value and appends it to the set.

It returns the set with the new entry.

Set.prototype.has takes a value and returns true if it’s in the set and false otherwise.

The Set.prototype.delete method takes a value and lets us remove it.

It returns true if it’s deleted and false otherwise.

The Set.prototype.size getter returns the number of items in the set.

The Set.prototype.clear method lets us remove all items from a set.

Set.prototype.values is a method that returns all values of a set as an iterator.

Set.prototype[Symbol.iterator] returns an iterable object that lets us iterate over a set.

The Set.prototype.forEach let takes a callback with the signature, (value, key, collection) as the signature, and runs it for each item in the set,

value has the set value.

key has the same value as value .

The collection is the set itself.

The 2nd argument is the value of this we use in the callback.

Sets also have the Set.prototype.entries method to return an iterable object with each entry being a key-value array.

The key and value are the same.

The Set.prototype.keys method returns us an iterable object with the keys, which is the same as the values.

WeakSet

A WeakSet is a set that doesn’t prevent its elements from being garbage collected.

It works like WeakMaps and doesn’t allow iteration, looping, or clearing.

There isn’t many uses cases for WeakSets.

We can add objects to them and then get them with the reference.

So we can write:

const weakSet = new WeakSet();

const obj = {};
weakSet.add(obj);
const hasObj = weakSet.has(obj);

We pass in a map and then check for its value with has .

We can only pass objects into a WeakSet.

We’ll get a TypeError if we try to pass in a primitive value.

Also, we can use WeakSets to allow us to run a method on a given class instance.

For example, we can write:

const bars = new WeakSet();

class Bar {
  constructor() {
    bars.add(this);
  }

  method() {
    if (!bars.has(this)) {
      throw new TypeError('not a bar instance');
    }
  }
}

We add the Bar instance to the bars WeakSet in the constructor.

Then in the method method, we check if the Bar instance if part of the WeakSet with has .

If it’s not, then we throw an error.

This prevents the method from being run on anything other than Bar instances.

WeakSet API

WeakSets has a simple API with 3 methods and works like their Set equivalents.

WeakSet.prototype.add takes a value as an argument and lets us add an entry to it.

WeakSet.prototype.has takes a value and returns true if the entry exists and false otherwise.

WeakSet.prototype.delete takes a value and removes the element from the WeakSet.

Conclusion

Sets let us add items without duplicating.

WeakSets let us hold items that can be garbage collected when they aren’t used.

Categories
Modern JavaScript

Best of Modern JavaScript — Iterables

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at JavaScript iterable objects.

Iterable Values

JavaScript has various kinds of iterable objects.

They include arrays, strings, maps, sets, and NodeLists.

Constructs Supporting Iteration

There’re various constructs that make working with iterable objects easier.

One of them is the destructuring syntax.

We can destructure any iterable object entries to variables.

For example, we can write:

const [a, b] = new Set(['a', 'b', 'c']);

Then we assigned 'a' to a and 'b' to b .

The for-of loop lets us iterate through entries in iterable objects easily.

For instance, we can write:

for (const x of ['foo', 'bar', 'baz']) {
  console.log(x);
}

to loop through an array.

The Array.from static method lets us create an array from iterable objects.

For example, we can convert a set to an array by writing:

const arr = Array.from(new Set(['a', 'b', 'c']));

Then arr would be [‘a’, ‘b’, ‘c’] .

The spread operator lets us do the same thing as Array.from

We can write:

const arr = [...new Set(['a', 'b', 'c'])];

to spread a set’s entries into an array.

The Map and Set constructor lets us create maps and sets from arrays.

The Map constructor takes an array with key-value arrays as entries and turn them into a set of key-value pairs in an object.

For example, we can write:

const map = new Map([
  ['foo', 'no'],
  ['bar', 'yes']
]);

To create a set, we can write:

const set = new Set(['a', 'b', 'c']);

to create it from an array.

Promise.all() lets us run multiple promises in parallel.

For instance, we can write:

Promise.all([
  Promise.resolve(1),
  Promise.resolve(2),
]).then(() => {
  //...
});

to run 2 promises in an array in parallel.

Promise.race resolves to the value of the first promise that finishes running.

For instance, we can use it by writing:

Promise.race([
  Promise.resolve(1),
  Promise.resolve(2),
]).then(() => {
  //...
});

And we get the first value resolved from the set of promises.

The yield* keyword lets us run generator functions from another generator function.

So we can use it by writing:

`yield*` `gen;`

Iterability

Any object with the Symbol.iterator method is an iterable object.

The method must be a generator function.

For example, we can get that method from the array by writing:

const arr = ['foo', 'bar', 'baz'];
const iter = arr[Symbol.iterator]();

Then we can get the entries one by one by calling the next method from the returned iterator:

iter.next()

We get:

{value: "foo", done: false}

when we run it the first time.

When we run it again:

iter.next()

We get:

{value: "bar", done: false}

Then when we run it again, we get:

{value: "baz", done: false}

Then finally, when we run it one last time, we get:

{value: undefined, done: true}

value is the value returned from the iterable object. And done indicates whether there’s any value to return.

next returns each item wrapped in an object.

Conclusion

JavaScript has various kinds of iterable objects.

They all have the Symbol.iterator property which is a method that returns the next value sequentially.

Categories
Modern JavaScript

Best of Modern JavaScript — WeakMaps and Sets

Since 2015, JavaScript has improved immensely.

It’s much more pleasant to use it now than ever.

In this article, we’ll look at weak maps.

WeakMap API

WeakMaps have 4 methods.

The WeakMap constructor takes an array of key-value pairs arrays.

The keys must be objects.

The WeakMap.prototype.get method takes the key and returns a value given the key.

WeakMap.prototype.set takes the key and value as arguments and returns the WeakMap with the new entry.

WeakMap.prototype.has takes the key as the argument and return true if the item with the given key exists and false otherwise.

WeakMap.prototype.delete takes the key with the item to delete and returns true if it’s deleted and false if it’s not found.

Set

ES5 doesn’t have a set data structure.

The alternatives are to use the keys of an object to store elements.

Or we can store the elements in an array.

We check whether it contains an element via indexOf or remove duplicates with filter etc.

indexOf can’t find the value NaN .

ES6 has the Set constructor to create a set.

It’s fast and handles NaN correctly.

We can create a set by writing:

const set = new Set();
set.add('foo');

We create a set with the Set construction and call add to add an entry.

The has instance method checks whether the item exists.

We can write:

const hasFoo = set.has('foo');

hasFoo is true since we have an entry with value 'foo' .

The delete instance lets us delete items.

For instance, we can write:

const deletedFoo = set.delete('foo');

It takes the key as the argument. It returns true if the item is deleted.

The size property has the number of items in the set.

So if we have:

const set = new Set();
set.add('foo');

const size = set.size;

And size is 1.

The clear instance method lets us remove all entries from a set.

For example, we can write:

set.clear();

Setting Up a Set

We can get the set by passing in an array into the Set constructor.

For example, we can write:

const set = new Set(['foo', 'bar', 'baz']);

We can also use the add method to add the items:

const set = new Set().add('foo').add('bar').add('baz');

The Set constructor has zero or one argument.

If no arguments are passed in, then an empty set is created.

If one argument is passed in, then the argument has to be an iterable object.

Comparing Set Elements

We can compare set elements with the has method.

The algorithm works like === but NaN is equal to itself

For instance, if we write:

const set = new Set([NaN]);

Then we can check if with:

consrt hasNaN = set.has(NaN);

Add the same element a second has no effect.

For example, we can write:

const set = new Set();
set.add('bar');
set.add('bar');

const size = set.size;

The size would still be one after we added 'bar' twice.

2 objects are never considered equal.

This behavior can’t be changed.

So if we write:

const set = new Set();
set.add({});
set.add({});

const size = set.size;

Then size is 2.

Conclusion

WeakMaps have a much simpler API than Maps.

Sets can’t have duplicate values, but objects are never considered the same even if they have the same content.