An utterly useless excercise in re-writing native JavaScript functions.
The general idea is to reverse-engineer JavaScript's inner workings, both to get a better understanding of how JavaScript works, and also to write easily-understandable code that any budding JavaScript code-monkey can look at and know what's going on.
While writing efficient code is ideal, this project is focussed on readability, and accurately recreating the functionality and quirks of how JavaScript works.
Each Unnecesary.js recreation has 5 js files included:
This file is written to be easy to read. Everything flows on from each other, variable names are self-explanatory, and comments explain exactly what is going on and why.
This does mean, however, that the code is very inefficient. This file is meant for reading, not executing. You can think of it as "pseudo-code", that happens to actually run.
This file is written as an efficient equivalent to commented.js. It keeps the same logic, but moves things around to run faster and leaner than it's predecessor.
This file is used in the index.html and comparison.html files for testing purposes.
This file takes verbose.js and makes the code as short as possible. Variables are single-characters, commonly-used property names and objects are proxied into short-named variables. The code is stripped down as much as possible but so that it runs exactly the same as the verbose.js version.
This file takes the terse code and strips out any unnecesary whitespace. The result is a hand-minified file that looks and behaves exactly like the commented.js, and therefore the original JavaScript method itself.
This code is efficient and as tiny as you can make it.
This file is simply used to test the different aspects of the implementation. It is used both in index.html and comparison.html.
JavaScript's Array.sort method has some quirks to it, but is essentially pretty straight-forward to understand. It was interesting to figure out how sorting works.
NOTE: browsers differ as to the sorting algorithm used. I basically wrote my own which is an amalgumation of a few of the classics. It's likely not all that performant, but it gets the job done, and demonstrates the issues involved nicely.
The code overwrites the native Array.prototype.sort method.
JavaScript uses a single-threaded process with non-blocking methods (as well as a few blocking
ones). The way timers (as in setTimeout or setInterval) work, and how they are affected by
functions that tie up the process too long, can be hard to get your head around at first but
again, once understood, they're pretty easy to remember and use to your advantage.
NOTE: I couldn't find any hard evidence for this, but apparently browsers differ in how they order their asynchronous callbacks and timers, etc. For the purposes of this project, I have gone with async-first, followed by timer events.
The code overwrites the setTimeout, clearTimeout, setInterval, and clearInterval
methods, as well as creating a new global method called setAsync, which can be used to
demonstrate how asynchronous callbacks are inserted into the event loop, and how the execution
of such callbacks can affected other queued events.
Type coercion is one of those things that just happens whether you like it or not, and if you aren't careful, your code could be doing a lot more than you thought it was. The Unnecesary.js code will re-implement different operators, showing how type coercion really works and what you should be aware of if you want to use it smartly.
In here are function implementations for the operators == (equal(a, b)),
!= (notEqual(a, b)), === (strictEqual(a, b)), !== (notStrictEqual(a, b)).
The logical operators (&&, ||, !) can be used for more than if statements and while loops. If
you know what you're doing, you can use the or operator to default values, for example.
The cloneNode method, available on every DOM Node, makes a full copy of the entire node. If you specify the optional deep parameter as truthy, then it will also clone all child nodes recursively. It will not, however, clone any javascript-based properties or events. Think of it as more of cloning the HTML, as opposed to the object-representation you see in JavaScript.
When an DOM event is triggered, registered listeners are called, being passed the relevant data for that event. There a few stages to this process, and this can affect the order and execution of each of the listeners.
(Source: http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases)
-
Capture Any listeners registered using the optional
useCaptureflag are called, starting with the highest DOM node in the tree, and working towards the target element. -
Target Listeners registered on the target element are then called, starting with the "capturing" listeners, and then the regular, "non-capturing" ones.
-
Bubbling Next, the event "bubbles up" the DOM tree, calling any remaining, non-capturing listeners.
-
Default Some elements have default actions that are triggered by certain events. For example, a checkbox element will show or hide the "tick" when the mouse "click" event is triggered.
The execution of these can be interrupted by any one of the listeners. The passed-in Event object has a couple of methods for the listener to use:
.stopPropagation()will stop the execution of any further listeners. (NOTE: this used to be called "cancelBubble" - which only stopped listeners that would be called suring the Bubbling phase - but has been changed in favour of this more general method.).preventDefault()will stop any default listeners from being called.