Last updated on 10th Jul 2020, Blog, Tutorials
- Lightweight, interpreted language.
- Easily embedded with languages like HTML, CSS, and Java.
- Also works as a client-side scripting language, which helps in creating dynamic web pages.
Advanced working with functions
Recursion and stack
Let’s return to functions and study them more in-depth. If you are not new to programming, then it is probably familiar and you could skip this chapter.
Recursion is a programming pattern that is useful in situations when a task can be naturally split into several tasks of the same kind, but simpler. Or when a task can be simplified into an easy action plus a simpler variant of the same task. Or, as we’ll see soon, to deal with certain data structures.
When a function solves a task, in the process it can call many other functions. A partial case of this is when a function calls itself. That’s called recursion.
A recursive (recursively-defined) data structure is a structure that replicates itself in parts.
We’ve just seen it in the example of a company structure above.
A company department is:
- Either an array of people.
- Or an object with departments.
For web-developers there are much better-known examples: HTML and XML documents.
In the HTML document, an HTML-tag may contain a list of:
- Text pieces.
- Other HTML-tags (that in turn may contain text pieces/comments or other tags etc).
That’s once again a recursive definition.
For better understanding, we’ll cover one more recursive structure named “Linked list” that might be a better alternative for arrays in some cases.
We already know that a function can access variables outside of it. Now let’s expand our knowledge to include more complex scenarios.
The global object provides variables and functions that are available anywhere. By default, those that are built into the language or the environment.
In a browser it is named window, for Node.js it is global, for other environments it may have another name.
Recently, globalThis was added to the language, as a standardized name for a global object, that should be supported across all environments. In some browsers, namely non-Chromium Edge, globalThis is not yet supported, but can be easily polyfilled.
We’ll use window here, assuming that our environment is a browser. If your script may run in other environments, it’s better to use globalThis instead. All properties of the global.
When passing object methods as callbacks, for instance to setTimeout, there’s a known problem: “losing this”.
Arrow functions are not just a “shorthand” for writing small stuff. They have some very specific and useful features.
- arr.forEach(func) – func is executed by forEach for every array item.
- setTimeout(func) – func is executed by the built-in scheduler.
- …there are more.
And in such functions we usually don’t want to leave the current context. That’s where arrow functions come in handy.
Decorators and forwarding, call/apply
Let’s say we have a function slow(x) which is CPU-heavy, but its results are stable. In other words, for the same x it always returns the same result.
If the function is called often, we may want to cache (remember) the results to avoid spending extra-time on recalculations.
But instead of adding that functionality into slow() we’ll create a wrapper function, that adds caching. As we’ll see, there are many benefits of doing so.
Decorators and function properties
It is generally safe to replace a function or a method with a decorated one, except for one little thing. If the original function had properties on it, like func.calledCount or whatever, then the decorated one will not provide them. Because that is a wrapper. So one needs to be careful if one uses them.
E.g. in the example above if slow function had any properties on it, then cachingDecorator(slow) is a wrapper without them.
Some decorators may provide their own properties. E.g. a decorator may count how many times a function was invoked and how much time it took, and expose this information via wrapper properties.
There exists a way to create decorators that keep access to function properties, but this requires using a special Proxy object to wrap a function. We’ll discuss it later in the article Proxy and Reflect.
Function object, NFE
Scheduling: setTimeout and setInterval
We may decide to execute a function not right now, but at a certain time later. That’s called “scheduling a call”.
There are two methods for it:
- setTimeout allows us to run a function once after the interval of time.
- setInterval allows us to run a function repeatedly, starting after the interval of time, then repeating continuously at that interval.
Generators, advanced iteration
Regular functions return only one, single value (or nothing).
Generators can return (“yield”) multiple values, one after another, on-demand. They work great with iterables, allowing to create data streams with ease.
Async iterators and generators
Asynchronous iterators allow us to iterate over data that comes asynchronously, on-demand. Like, for instance, when we download something chunk-by-chunk over a network. And asynchronous generators make it even more convenient.
Let’s see a simple example first, to grasp the syntax, and then review a real-life use case.
Methods of primitives
Let’s look at the key distinctions between primitives and objects.
- Is a value of a primitive type.
- There are 7 primitive types: string, number, bigint, boolean, symbol, null and undefined.
- Is capable of storing multiple values as properties.
- BigInt numbers, to represent integers of arbitrary length. They are sometimes needed, because a regular number can’t exceed 253 or be less than -253. As bigints are used in few special areas, we devote them a special chapter BigInt.
So here we’ll talk about regular numbers. Let’s expand our knowledge of them.
The internal format for strings is always UTF-16, it is not tied to the page encoding.
Objects allow you to store keyed collections of values. That’s fine.
But quite often we find that we need an ordered collection, where we have a 1st, a 2nd, a 3rd element and so on. For example, we need that to store a list of something: users, goods, HTML elements etc.
It is not convenient to use an object here, because it provides no methods to manage the order of elements. We can’t insert a new property “between” the existing ones. Objects are just not meant for such use.
There exists a special data structure named Array, to store ordered collections.
Iterable objects is a generalization of arrays. That’s a concept that allows us to make any object useable in a for..of loop.
Of course, Arrays are iterable. But there are many other built-in objects, that are iterable as well. For instance, strings are also iterable.
If an object isn’t technically an array, but represents a collection (list, set) of something, then for..of is a great syntax to loop over it, so let’s see how to make it work.
Map and Set
Now we’ve learned about the following complex data structures:
- Objects for storing keyed collections.
- Arrays for storing ordered collections.
But that’s not enough for real life. That’s why Map and Set also exist.
WeakMap and WeakSet
Object.keys, values, entries
Let’s step away from the individual data structures and talk about the iterations over them.
In the previous chapter we saw methods map.keys(), map.values(), map.entries().
These methods are generic, there is a common agreement to use them for data structures. If we ever create a data structure of our own, we should implement them too.
They are supported for:
Plain objects also support similar methods, but the syntax is a bit different.
Objects allow us to create a single entity that stores data items by key, and arrays allow us to gather data items into an ordered collection.
But when we pass those to a function, it may need not an object/array as a whole, but rather individual pieces.
Destructuring assignment is a special syntax that allows us to “unpack” arrays or objects into a bunch of variables, as sometimes that’s more convenient. Destructuring also works great with complex functions that have a lot of parameters, default values, and so on.
Date and time
Let’s meet a new built-in object: Date. It stores the date, time and provides methods for date/time management.
For instance, we can use it to store creation/modification times, to measure time, or just to print out the current date.
JSON methods, toJSON
Let’s say we have a complex object, and we’d like to convert it into a string, to send it over a network, or just to output it for logging purposes.
Naturally, such a string should include all important properties.
“Don’t use frames.” is an oft repeated advice in web developing. The disadvantages of using frames are many…
- Pages inside a frameset are hard to bookmark.
- Other sites won’t be able to link to a page in a framed site.
- Search bots find it hard to go through a framed site
- Users can’t type in the url of a deep page.
- And more…
But one could use frames in web designing if the designer gives a no-frame alternative for the site. www.quirksmode.org is a good example of how to do this. That said, let us continue with our tutorial.
HTML frames allow authors to present documents in multiple views, which may be independent windows or subwindows. Multiple views offer designers a way to keep certain information visible, while other views are scrolled or replaced. For example, within the same window, one frame might display a static banner, a second a navigation menu, and a third the main document that can be scrolled though or replaced by navigating in the second frame.
Moving Stuff around
- Maximum Cross-Browser Compatibility
- More structure to the code
- Increased Readability
- Increased Reusability
- World Peace
I had ignored some or most of the principles said here in my earlier scripts because I want to keep those examples as simple as possible. I am including these here so that when you program you will do it with the best possible methods. Please remember that these are not ironclad rules but rather helpful principles.
Object properties configuration
Property flags and descriptors
As we know, objects can store properties.
Until now, a property was a simple “key-value” pair to us. But an object property is actually a more flexible and powerful thing.
In this chapter we’ll study additional configuration options, and in the next we’ll see how to invisibly turn them into getter/setter functions.
Property getters and setters
There are two kinds of object properties.
The first kind is data properties. We already know how to work with them. All properties that we’ve been using until now were data properties.
The second type of property is something new. It’s accessor properties. They are essentially functions that execute on getting and setting a value, but look like regular properties to an external code.
Class inheritance is a way for one class to extend another class.
So we can create new functionality on top of the existing.
Static properties and methods
We can also assign a method to the class function itself, not to its “prototype”. Such methods are called static.
Private and protected properties and methods
One of the most important principles of object oriented programming – delimiting internal interface from the external one.
That is “a must” practice in developing anything more complex than a “hello world” app.
To understand this, let’s break away from development and turn our eyes into the real world.
Usually, devices that we’re using are quite complex. But delimiting the internal interface from the external one allows to use them without problems.
Extending built-in classes
Built-in classes like Array, Map and others are extendable also.
Class checking: “instanceof”
The instanceof operator allows to check whether an object belongs to a certain class. It also takes inheritance into account.
Such a check may be necessary in many cases. Here we’ll use it for building a polymorphic function, the one that treats arguments differently depending on their type.
But sometimes that feels limiting. For instance, we have a class StreetSweeper and a class Bicycle, and want to make their mix: a StreetSweepingBicycle.
Or we have a class User and a class EventEmitter that implements event generation, and we’d like to add the functionality of EventEmitter to User, so that our users can emit events.
There’s a concept that can help here, called “mixins”.
As defined in Wikipedia, a mixin is a class containing methods that can be used by other classes without a need to inherit from it.
In other words, a mixin provides methods that implement a certain behavior, but we do not use it alone, we use it to add the behavior to other classes.
I love deadlines. I especially like the whooshing sound they make as they go flying by.
But finally in August I managed it – I have completed the tutorial.
- The XMLHTTPRequest method – AJAX framework
- getElementsByTagName() Method
- Changing Stylesheets dynamically.
- Associative Arrays
- Writing and implementing Browser Specific Code
- And More…
Some day I may be able to write a tutorial for these stuff – but I don’t think it will be anytime soon. I will not suggest that you wait for me. I think it is better for you to search and study about them by yourself. There are a lot more tutorials out there. Find them and learn from them.