- Security
- Abstraction / High-level Constructs
- Scoping / How Could it be Better?
Scoping
JavaScript was intended as a scripting language. The name (although not the original name for the language) was adopted because Netscape thought that it would be used primarily for scripting Java Applets and connecting them to the rest of the page. You could use JavaScript to modify things on the page in response to events from within the applet, and vice versa.
As such, the lack of scoping was not a problem. Scripts were expected to be a few dozen lines long, not the multi-megabyte monstrosities that you see on the web today.
When coming from almost any other language, this lack of scoping is a problem. Something like C++ has horrendously complex scoping rules, but even C allows you to define file-local (static) variables.
Of course, you can define an object called CFiles (or whatever), define a property for each source file, and then store static variables in its fields. The problem, once again, is that every something-to-JavaScript translator needs to implement a mechanism like this. There is no equivalent of the ELF visibility and linkage types for representing these different scopes.
This is also a slight problem when compiling file-based languages to JavaScript. In C++, for example, it is common to put some template functions in a header. These functions are compiled for every file that includes the header and calls them and emitted as link-once, on definition rule, symbols. The linker then strips off duplicate definitions. Doing this in JavaScript is a very complex task indeed...
How Could it be Better?
Garbage collection, while not essential for languages like C, is not necessarily a bad thing. With my Objective-C to JavaScript translator, you can do things such as return a pointer to something allocated on the stack and have it actually work because both 'stack' and 'heap' allocations are implemented using garbage-collected memory. In code that is intended to run in web applications, I prefer a little bit of extra safety and resilience to programmer error, even if it's at the cost of some speed. I would, however, like to see weak references or some equivalent mechanism.
The object model is not bad, but I would love to see something more like the COLA (combined object-lambda architecture) model from the Viewpoints Research Institute. It is very close to the JavaScript model, but it makes the mapping from selector (method name) to method the responsibility of the object. In effect, an object is a closure that returns a method. This is quite easy to implement in JavaScript, and JavaScript is easy to implement in this model. Making this the underlying representation for existing JavaScript objects would make it easy to plug in other object models without breaking JavaScript.
The other major problem with JavaScript as a compiler target, of course, is the syntax. A significant amount of time in a JavaScript implementation is spent in the parser. Worse, the lack of modularity means that the entire program must be tokenized and parsed before any of it can be executed.
Contrast this with a Smalltalk or Java virtual machine, where classes can be lazily read as they are first instantiated. When compiling from another language, you often have a lot of compatibility code to load, which makes it even worse.
Rather than continue to enhance JavaScript, I would love to see some standards effort directed at defining a portable bytecode format that would provide a more language-agnostic target for different compilers.