March 11, 2011

JavaScript for Pythonistas

My first extreme talk, and Ian Bicking is always worth a listen. Because it's extreme, no intro to JavaScript. "It's a small, simple language with some weird things that are totally understandable." Ian wants to focus on what the language does rather than why it does it.

JavaScript is easily accessible to Python programmers, but the data structures can be tricky. Arrays are like Python lists, objects are like Python dicts. Objects can be fairly lightweight, and can be passed around. Keys are always strings, -- subscripted notation and attribute notation are equivalent. Exceptrions work very similarly to Python, but JavaScript programmers don't use them anywhere near as extensively.

Function declarations are fairly intuitive, but unlike in Python an undeclared variable is assumed to be located in some "containing" scope, and the var keyword causes them to be bound locally. Function arguments are always optional, and parameters for which there is no corresponding actual argument will be undefined. Undefined is "falsish", and we have to use typeof(name) == "undefined" to test for this.

Object classes are created by prototype, which is more like Self, or perhaps Ruby, than Python. The new operator is the only way to effectively create new instances. A function call implicitly binds to the variable this, but without new the binding will be to some global object (in a browser typically the document or the window). The inheritance hierarchy is handled similarly to Python except that instance creation calls the prototype function using new. It's not, therefore, as simple to use factory functions and classes interchangeably - though it can be done if you work.

The this object is almost comparable to Python's self, but the way JavaScript figures out what value it takes is, Ian submits, insane. With no equivalent to Python's bound methods, and method calls are determined syntactically. Consequently assigning an object's method to a local variable will cause this to be computed completely differently depending on whether the method is called directly or through the local variable. This is also problematic when closures are used to create private data stores. You can sometimes overcome it my saving this for later use (Ian chose the name self for the local variable he used to do this).

Functions have .call() and .apply() methods, whihc you can use to call them in specific ways.

Monkey patching should be avoided.

Types are one of the aspects of JavaScript makes least sense to people. It has numbers, strings and Booleans. The language also has the same kind of distinction between primitive and boxed values that Java does. There should really be no need to use the classes that wrap the primitive types. This gives rise to strange non-intuitive rules that are applied during comparisons. The "===" operator is similar to Python's is.

Arrays are disappointing to Python users, being a pale shadow of the Python list. There is not iteration protocol, and no test for containment of a value within a list.

Much of JavaScript's applications work on the browser Document Object Model (DOM). C++ is responsible for the DOM's complexity. The language is improving, but the new features are only slowly working their way into implementations. Many newer features have been inspired by, among other languages, Python.

If you like Python, you might want to try using CoffeeScript. It is more whitespace sensitive than Python, and handles arrays better than JavaScript.

Alas, time for only a few questions:

Q: What do you recommend as the closest equivalent in JavaScript to Python's interactive console. A: Firebug and the like.

Q: What does inheritance look like with prototypes?
A: If a prototype has a prototype that is essentially subclassing.

2 comments:

Karl said...

The best reference for JS is:

http://bonsaiden.github.com/JavaScript-Garden/

The behavior of `this` isn't THAT screwy but the design flaw that makes people think it's screwy pops up quite often.

alex dante said...

I've been using CoffeeScript for a few months now and it's practically indispensable.

Apart from the whitespace sensitivity, it adds a heap of features helpful to a Python dev, like comprehensions, array slicing, easier variable argument handling for functions, and a simple class model that wraps prototyping.