Evolve JavaScript, don't reinvent it

written on Tue, 08 May 2007 22:03

It's interesting how much buzz is out there about JavaScript currently. And you can read about possible successors more often as it seems. But i doubt that adding keywords like class or packages to that language would make it better.

JavaScript is a great language! But there are many design mistakes in, but probably different mistakes than you think. Having no class syntax etc is not a flaw, it's genious. Also one namespace is no issue at all since you can easly add closures around your stuff and return one element to the global namespace that has multiple members and substructures. This works pretty much like ruby namespaces if used in a sane way.

But where are the mistakes then?

this

this is the biggest mistake in that language. It always points to something and in most situations it points to the global namespace which makes no sense since it makes working with closures a lot harder.

In a situation where you call a function without sending a message from an object (just bar() and not foo.bar()) this should point to the this of the scope where the function is defined in:

/* current solution, one has to bind this to a different variable */
MyNamespace.User.makeCounter() {
  var counter = -1;
  var self = this;
  return function() {
    if (self.userCounter > counter)
      counter = self.userCounter;
    return ++counter;
  }
}

/* would make much more sense when this points to the outer this: */
MyNamespace.User.makeCounter() {
  var counter = -1;
  return function() {
    if (this.userCounter > counter)
      counter = self.userCounter;
    return ++counter;
  }
}

Inheritance

Inheritance in JavaScript works via prototypes. But it doesn't work in a nice way because there is no syntax for it. It would help if you have a syntax for inheriting stuff:

/* old school inheritance by setting the internal link to
   an existing object by creating a new instance of an object: */
MyNamespace.NewClass = (function() {
  var cls = function() {};
  cls.prototype = MyNamespace.ParentClass;
  cls.fooMethod = function() { ... };
  cls.barMember = 42;
  return new cls();
})();

/* with syntactic sugar: */
MyNamespace.NewClass = MyNamespace.ParentClass >> {
  fooMethod : function() { ... },
  barMemner : 42
};

That syntax might not be the best one but it says what happens. If if there is no syntax, at least there should be a factory function that does something similar (Object.extend).

More Functional Helpers

JavaScript is a functional language. That's what the intenion was and what it does best. So please add partial/curry, map and some other helpers either to the global namespace or to the arrays/functions itself.

Better Lambda

JavaScript has a function keyword that works exactly like a lambda should work. But it could be better by removing that keyword or making it a lot smaller. Possible solutions:

/* current solution */
var result = map([1, 2, 3, 4], function(item) {
  return item * item;
});

/* ruby like solution */
var result = map([1, 2, 3, 4], { |item| item * item });

/* just making the keyword smaller */
var result = map([1, 2, 3, 4], def(item) { return item * item });

As you can see one of them has implicit defaults. And the ruby like solution would rewrite the pipe symbols, even if no arguments are passed because otherwise it would have a different meaning.

Iteration

JavaScript iteration works the wrong way. Especially since arrays are objects and iterate over their keys which is wrong and silly. Do what ruby does, call `each()` and pass it a function:

/* old solution for array iteration */
for (var i = 0, n = foo.length; i < n; i++) {
  var item = foo[i];
  ...
}

/* old solution for object iteration */
for (var key in foo) {
  var value = foo[key];
  ...
}

/* ruby like solution for iteration */
for (var key, value in foo) {
  ...
}

/* which would be the same as */
foo.each(function(key, value) { ... })

This of corse raises the question how continue and break should work then. The continue statement would translate to return and break to throw new StopIteration().

Everything as Object / Operators

Throw away that stupid typeof operator and make Numbers, Booleans null, undefined whatever objects. Operator overloading would be a nice to have but it would make things much more complicated. At least the + Operator should not add and concatenate at the same time. The simple rshift Operator would be extend for other objects as seen above.

Also == should become === and vice versa. Likewise for != and !==.

Conclusion

This might not be the answer but it makes a lot more sense for a web centric language (which JavaScript certainly is) than another Java like language implementation.

view page source