This is true only for a very particular kind of constants, like the ones defining API error codes (eg. define PAGE_NOT_FOUND 404). And those should be covered by integration tests, not unit tests.
To expand on this, the tool of choice for the frontend part used to be PrototypeJS. In Rails 3.1 the relevant portions were decoupled and became options rather than baked-in, with jQuery as the default but still an option among several: http://weblog.rubyonrails.org/2011/4/21/jquery-new-default/
I'd like to point a possible flaw in your counter-argument: jQuery wasn't the only choice and it wasn't the first. PrototypeJS, which came before it, did an arguably better job since it didn't have many of jQuery's design flaws, like hijacking 'this' or silent selector errors.
The PHP analogy is therefore spot on IMHO: both it and jQuery (and I'd like to throw MySQL in there while we're at it) were tools that achieved success by lowering the quality bar in exchange for feature abundance and "if it works why do you care how".
There were a few CGI script websites around, like Matt's Script Archive and his (in)famous FormMail.pl.
There were also URL libs, eventually, as well as other CGI-specific tools, like counters, banners etc.
You are right that PHP was the logical simpler choice, and it did take off in the second half of the 90s. But for the best part of the decade the web was built on CGI.
I would argue that the CGI era was a good one. Writing a CGI required low-level knowledge of HTTP, HTML, how web servers worked, and very likely knowing your way around a UNIX system. Solid skills, that are still useful today, marked a high bar which raised the overall level.
Furthermore, the nature of CGIs made for better architectures. Simple entry and exit points, dedicated services. Connecting them to something else required careful consideration. They made you gravitate naturally towards KISS, REST and other best practices which are still observed today.
I would also add that there were several other hobbyist fields popular at the same time, like MUDs (usually built in C) or IRC servers/clients/bots (also Perl/C/TCL) to name just a couple. Knowledge gained in one of them lent itself fairly easily to another.
Use console.dir(var) for a moment-in-time snapshot. The side panel you get when you click on a var is a debug view, which is a lot more useful as a "live" value watcher.
And if you need an online tool while away from your computer, http://getvideo.at/ is running on youtube-dl. It will parse the given webpage and list out direct download links.
I don't see what "regular people" has to do with it... you either know how your filesystem works or you don't. I you don't, the Linux way (I deleted a file but it's still in my editor) can be just as confusing as the Windows way (I can't delete or move or rename this file because it says it's in use, but I don't have any programs open that use it).
It's still going to be XML. JSON is fairly limited, it's literally the serialization format for JavaScript variables, and that one size does not fit all.
I suspect we may be talking about two different approaches. Nobody _wants_ to trip on a null reference, naturally. But there are different ways of achieving that, and some of them yield additional benefits.
One way is to forbid them outright (which is what Tony Hoare regretted not doing when he made the "billion dollar mistake" presentation IIRC).
Allowing them to run unchecked is obviously not a good idea.
The "null object pattern" is another option, where the nulled var will be replaced on the fly with a "mock" that will not cause any trouble.
Here's another approach. It's more convoluted and you need the language to help you with it (Java does), but it return it offers the benefits described in my previous post:
* Implicit nulls across the board.
* No penalty if the nulled variable is not used in an ambiguous manner (passing-on and checking the reference are ok).
* Consistent runtime fail-fast behavior if the nulled variable is used in a manner that requires the declared type. (Java throws an exception, which uncaught leads to the stop of the program, thus preventing undefined behavior, but also allows the programmer to catch and recover.)
* Most importantly: you DO NOT check for nulls with inline checks or assertions, but instead rely on unit tests to validate intended behavior.
The technique is called "passing nulls" in UT.
The end result is a more "relaxed" code, which promotes loose coupling and leads to more flexible code paths, which in turn make possible additional patterns. If you're not hurting anything by nulls why be forced to conform to rigid declarations? And if you are hurting something, then you will be forced to deal with it in a consistent manner.
Unfortunately they decided to go with explicit nullables instead of implicit, which means that you still have to go and write/modify all your code explicitly to benefit from this. Which pretty much negates the benefit.
Implicit nullables across the board are extremely useful when designing loose-coupled and natively unit-testable code. They allow you to design code paths with a minimum of fuss (don't worry about a parameter if you're not actually using it right now), they allow you to substitue simple nulls instead of mocks, and can help to deep-map code paths and use cases for specific parameters.
Another issue is the inconsistent manner of dealing with errors generated when attempting to use a parameter as its actual non-null type. They range from notices to fatal errors (non-catchable with try). By contrast, in Java you consistently get a "null pointer exception" when this happens (and Java also has implicit nullables).