Skip to main content
jonas thiem.

String.prototype.blink() and other Netscape fossils

Why is there a String.prototype.blink()? And other questions from 30 years of JavaScript.

An HTML blink element saying "Now you see me and continue to do so." Thank you, I'm here permanently, unblinkingly.
An HTML blink element saying "Now you see me and continue to do so." Thank you, I'm here permanently, unblinkingly.

Yesterday, I was one of ten thousand and learned about HTML wrapper methods in JavaScript while using the autocomplete of Firefox’s devtools on a string. They do exactly what it says on the tin: they wrap strings in HTML tags. These functions are essentially:

javascript
function wrapInHtmlTag(str, tag, attr, attrValue) {
    var attribute = ""
    if (attr && attrValue) {
        attribute = " " + attr + "=" + '"' + attrValue + '"'
    }
    return "<" + tag + attribute + ">" + str + "</" + tag + ">"
}

Except each is a separate function as part of the prototype of the JavaScript String object. They are part of the ECMAScript spec and exist even in Node.js — keep that in mind for the next Express.js site you write. There are also only a select few available: only thirteen wrapper methods exist while there are 141 HTML elements in the current standard.

Besides being a very odd thing to have part of the basic string object, more than half of the functions produce obsolete markup according to the HTML spec. Seven of the thirteen or 53%. That’s a considerably higher percentage of obsolete elements than the “general population” of elements: of the 141 elements available today, only 29 are marked as obsolete, which comes out to 21% 1. Even 21% is already more than I had imagined.

HTML wrapper methods
function output obsolete?
anchor(name) <a name="name">…</a> yes
big() <big>…</big> yes
blink() <blink>…</blink> yes
bold() <b>…</b> no
fixed() <tt>…</tt> yes
fontcolor(color) <font color="color">…</font> yes
fontsize(size) <font size="size">…</font> yes
italics() <i>…</i> no
link(url) <a href="url">…</a> no
small() <small>…</small> no
strike() <strike>…</strike> yes
sub() <sub>…</sub> no
sup() <sup>…</sup> no

The two functions that jump out to me are String.prototype.blink() and String.prototype.anchor().

There is already very little utility in HTML wrapper functions to begin with, but the usefulness of the blink function is reduced further by the fact that no browser implements the blinking part of the <blink> tag anymore. This is what a blink tag currently renders like in your browser: blink.

I tested this in Safari and Firefox and both sadly — or luckily depending on your view of the world — no longer blink obnoxiously. Of course, just because the browser no longer ships an animation for <blink> by default doesn’t mean you couldn’t go and create one. Thanks to modern CSS animations, getting the blink back is only a few lines of stylesheet away. I don’t recall the last time that I have seen blinking text on the web. It appears that, beyond the cultural impact among web developers, <blink> is not really missed by anyone.

String.prototype.anchor() creates the strange-looking <a name="anchor"> element. Originally this was intended to serve the function that the id attribute serves in modern contexts: you can link to it with <a href="#anchor">. I had not been aware of the origin of the <a> element, or if I was I had already forgotten it again: initially, both sides of a link were anchors. It seems like id was an easy winner. But given this context, it makes (a little) more sense that linking is done via <a href>.

Interestingly MDN claims that the anchor function doesn’t produce valid markup and that the HTML spec doesn’t allow anchor elements to have a name attribute. The “Obsolete features” portion of the HTML Standard is a tiny bit softer in its language: “obsolete but conforming feature.” It recommends that conformance checkers warn about its usage. Irrespective of that, current browsers still support <a name>.

Linking to an anchor name demo

But why? Why would there be functions that wrap a string in HTML tags? Because of how people in the mid-to-late 90s used JavaScript: document.write().

Admittedly, I am going off of how “Official Netscape JavaScript 1.2 book” by Peter Kent advises JavaScript to be used and some of my own intuition given the tools available. The book and this era of JavaScript and Netscape predate me and I am just trying to put together the pieces.

The best way I can describe it is that the book presents JavaScript in a similar way to how PHP worked in those days. Compare these two examples:

html
<p>
    Your current account balance is now
    <script>
        var balance = 10
        balance = balance - 3
        document.write(balance.toString().bold())
    </script>
    €.
</p>
php
<p>
	Your current account balance is now <b><?php
		$balance = 10;
		$balance = $balance - 3;
		echo $balance;
	?></b>€.
</p>

In both cases the “web developer” writes regular HTML, interspersed with a scripting language to create more powerful documents. It’s interesting how similar in their model these two are.

This model also explains one of the aspects of JavaScript that I always found confusing. By the time I started learning web development, JavaScript was less about writing documents and more about modifying the existing DOM. I was taught to put my <script src> tag at the end of the document because JavaScript was parsed synchronously and a script tag forces the browser to stop parsing the HTML and start parsing and executing the JavaScript.

That seemed bizarre at the time, but now looking at the way document.write() is used in the Kent book, I get it: that behavior made sense in a different time. The browser had to execute the JavaScript to see if it injected any writes of its own into the document stream.

Both languages also moved in the same direction: from being just a way to enhance HTML markup to proper application development. Some lament that the web has become a place for experts only and part of that is how complicated the average web application has become. I don’t think that is literally true. After all, you can go to Neocities and have the same level of fun as you did back in the day. But it is true that “serious” uses of both PHP and JavaScript have indeed moved past what an interested person can learn in a weekend.


Speaking of “learning JavaScript in a weekend,” this post wasn’t meant to take me more than a weekend to write. However, by the end I found myself skimming through parts of that Netscape JavaScript 1.2 book 2. Certainly not where I thought an autocompletion on a string would lead me. There are a few highlights I would like to share from the book.

Starting on page 9, there are a few examples of what JavaScript can be used for. Among other things, it features an “unusual” calculator; unusual because it uses an image of a real calculator — if you can believe it. Impressive indeed.

The bozo filter was another rabbit hole. The link printed in the book still works and the page seems to be part of an actual feud between real people? The script shared on that page is still possible to implement, but the exact implementation of the bozo filter doesn’t work anymore. Browsers no longer reveal the exact URL a user came from when navigating cross-origin, so the script will never see the URLs it’s looking for. Both the MDN page for document.referrer and MDN page for Referrer-Policy are worth reading if you want to learn more. I wonder how often that script has been independently reinvented and if there are any good uses of document.referrer.

Another interesting tidbit is the use of history.back() in that script. I had no idea the History API was that ancient. Of course, the modern history.pushState() and friends, which ended up replacing the old “hashbang” method of SPA routing, didn’t exist yet.

Also seen in the bozo filter script above: you can use <!-- html comments to hide the contents of <script> from browsers that do not understand it, like the commonly used Internet Explorer 2. This is still true today — the HTML comments in <script>, not IE2 thankfully — and apparently way messier than I had imagined. I don’t dare pretend that I understand what the HTML spec says about HTML comments in script elements, but have a look for yourself and see if you can decode it.

This appears to be only a concern for inline scripts, not for scripts linked to with <script src>, so this shouldn’t unlock a new fear of accidentally breaking a script by writing if (x<!--y) { ... }. Frankly, that should be an old fear: please use prettier to format your JavaScript and just don’t write code that has even a passing resemblance to that … please.

The last thing I thought was worth highlighting is this quote from where Kent compares Java and JavaScript, which I suppose was a sensible thing to do back in the day since Java applets could be embedded into a web page:

JavaScript is more appropriate for relatively simple uses. You won’t build a word processor using JavaScript!

— Peter Kent, Official Netscape JavaScript 1.2, p. 6

It’s amusing that this sentiment has both survived into the modern day and turned out to be entirely wrong. As with all my posts, this was written in Obsidian, a JavaScript word processor.

  1. number of elements

    I got these (very scientific) numbers by scraping the HTML Living Standard:

    The index of the HTML standard has a list of all elements and after I fiddled around in the web console I got:

    javascript
    Array.from(
        document.querySelectorAll("#element-interfaces + p + table > tbody > tr > td:first-child"),
    ).map((el) => el.innerText)

    This script returns an array of length 113. This includes one row for “custom elements” hence the final number of current elements is 112. I am sure there is a better way; the search algorithm in my head has no guarantees beyond “it’s solution-shaped.”

    The 29 number comes from the table of non-conforming elements and this short script:

    javascript
    Array.from(document.querySelectorAll('dl [data-dfn-type="element"]')).map((el) => el.innerText)

    The above script returns an array of length 26 and after adding <frame>, <frameset>, and <marquee> elements, which for reasons unknown to me do not get a mention in the list I queried, we get 29.

    Combined that makes 141 elements, 112 current and 29 obsolete. ↩︎

  2. netscape javascript

    If you are curious about how ancient JavaScript was written and written about, you can borrow the book from OpenLibrary. The HTML wrapper methods are written about on page 218 and a little about document.write() on page 331, although it’s prevalent throughout the entire book. The examples starting on page 9 are worth skimming too, in my opinion. ↩︎