Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62
Subscribe to my email list now at http://jauyeung.net/subscribe/
JavaScript lets us do a lot of things. It’s sometimes too forgiving in its syntax.
To organize our code, we should use some basic design patterns. In the article, we’ll look at factories, iterators, and decorators.
Built-in Object Factory
JavaScript’s standard library comes with several factory methods.
They include Object
, Boolean
, Number
, String
, and Array
.
For instance, we can use the Boolean
factory function as follows:
const bool = Boolean(1);
Then bool
is true
since 1 is truthy.
All they do is return different objects or values according to what we pass in.
Many of them are useful. However, the Object
constructor isn’t all that useful since we can create objects with object literals.
Iterator
JavaScript has iterators since ES6.
Therefore, we don’t have to write anything from scratch to implement this pattern
We just have to use a generator function to return the values we’re looking for sequentially.
Then we can call the built-in next
function to get the value returned after the generator is returned from the generator function.
For instance, we can write:
const numGen = function*() {
while (true) {
yield (Math.random() * 100).toFixed(1);
}
}
to create a generator function.
A generator function is denoted by the function*
keyword. There’s an asterisk after the function
keyword.
The yield
keyword will return the next value sequentially.
Then we can use it to return a random number as follows:
const nums = numGen();
console.log(nums.next().value);
console.log(nums.next().value);
console.log(nums.next().value);
We first call numGen
to return an iterator.
Then we call nums.next().value
to get the values we want.
We can also have a generator function that returns a finite number of values.
For instance, we can write:
const numGen = function*() {
const arr = [1, 2, 3];
for (const a of arr) {
yield a;
}
}
const nums = numGen();
let value = nums.next().value;
while (value) {
console.log(value);
value = nums.next().value;
}
In the code above, we changed the numGen
function to return an array’s entries in sequence.
This way, we can call the next
method in a loop to get the entries in sequence with the next
method.
In addition to value
property, the object returned by the next
method also has the done
property.
So we can write:
const nums = numGen();
let {
done,
value
} = nums.next();
while (!done) {
console.log(value);
const next = nums.next();
done = next.done;
value = next.value;
}
Once all the values are returned, done
will be set to true
.
Additional Functionality
If we want more functionality, then we’ve to implement our own iterator.
For instance, if we want rewind functionality, we can create our own iterator as follows:
const iterator = (() => {
const arr = [1, 2, 3];
let index = 0;
return {
next() {
index++;
return arr[index];
},
rewind() {
index--;
return arr[index];
}
}
})();
We just added an array with the next
method to move to the next arr
entry and rewind
to move to the previous arr
entry.
Then we can use iterator
as follows:
console.log(iterator.next());
console.log(iterator.rewind());
And we see:
2
1
from the console log output.
Decorator
Decorators let us add functionality to an object on the fly.
JavaScript has decorators now so that we can use them to create our own decorator and mutate objects on the fly.
For instance, we can create one as follows:
const foo = () => {
return (target, name, descriptor) => {
descriptor.value = "foo";
return descriptor;
};
};
class Foo {
@foo()
bar() {
return "baz";
}
}
const f = new Foo();
console.log(f.bar);
A decorator in JavaScript, it’s just a function that returns a function with the parameters target
, name
and descriptor
.
descriptor
is the property descriptor, so we can set the value
, writable
, and enumerable
properties for it.
Our foo
decorator transformed the value
property of it to the string 'foo'
.
So we get that Foo
instance’s bar
property becomes the string 'foo'
instead of a method.
JavaScript decorators are still experimental syntax, so we need Babel to use it.
Conclusion
JavaScript has various factory functions that let us create objects.
There’s the Object
, Boolean
, Number
, String
functions and more.
JavaScript has built-in support for iterators. However, if we want more functionality that it provides, then we’ve to implement our own.
Decorators exist in JavaScript, so we can use it to create decorators to modify properties.