JavaScript gotcha's for Pythonistas
Someone has to build the UI and today it's you.
In many ways JS is similar to Python. So similar than when it's not, it might surprise you. Below are some things I found intersting in two solid months of javascripting.
Object declarations and attribute access
In JS the closest thing to Python's dict
s are Object
s.
// this is the same in both JS and Python
mything = {'foo': 1, 'bar': {'x': 5}}
// this is not
mything = {foo: 1, bar: {x: 5}}
// but both are the same in JS!
Python will take your key literals and treat them as variable names. JavaScript will turn them into strings and use them as key names! What's more fun, it only does that for keys, not the values.
foo = 1
python: {foo: foo} => {1: 1}
javascript: {foo: foo} => {'foo': 1}
There is an upside to that — you don't have to use quotes so much:
// instead of this
x = {'foo': 1};
x['bar'] = 2;
// just do this
x = {foo: 1};
x.bar = 2;
And a downside — using variables as key names requires a little dance:
mykey = 'foo';
x = {};
x[mykey] = 1;
Attribute access
JS is very relaxed about that, there is the famed dotted notation. Python has no built-in equivalent. The upshot is that any nested attribute can be accessed by a single dotted selector:
// instead of
mything['foo']['bar'][0]['x'] = 5;
// simply do
mything.foo.bar.0.x = 5
Notice this works for array indexes too. Of course, variable key names will still require []
.
Unfortunately, this has to be a literal. There is no built-in way to do mything['foo.bar.0.x']
.
Missing attributes
(updated 10.13)
Unlike Python, JS always returns attribute values, even the missing ones. The missing attributes miraculously have values, and their value is undefined
. This can be handy:
// naively in Python:
value = False
if 'maybe_there' in obj:
value = obj['maybe_there']
if value == 2: ...
// skillfully in Python:
if obj.get('maybe_there', None) == 2: ...
// in JS:
if (obj.maybe_there == 2) { ... };
Of course, you can only take this one level deep:
> obj = {}
{}
> obj.foo
undefined
> obj.foo.bar
TypeError: Cannot read property 'bar' of undefined
Object comparisons
A colleague pointed this out to me, objects do not compare:
> {'a': 1} == {'a': 1}
false
> {'a': 1} === {'a': 1}
false
Thanks.
for (var i in things) {
Despite how straightforward and intuitive that looks, it is not.
If things
is an Object, i
will iterate over key names. Ok, fine.
If things
is an Array, i
should iterate over elements, right? Wrong. i
will iterate over array indexes.
If i
iterates over array indexes those should be integers, right? Sometimes. Sometimes it's a string representing an integer!
Handle this however you like, just beware.
};
JavaScript can't handle the truth
Oh yeah. Your if
statements are not doing what you expect and you begin to wonder why.
> Boolean('')
false
Good, we were expecting that. That means our habit carries over, right?
> Boolean({})
true
> Boolean([])
true
Nope.
_.isEmpty()
Does Underscore have anything handy? isEmpty()
looks useful:
> _.isEmpty('')
true
> _.isEmpty([])
true
> _.isEmpty({})
true
> _.isEmpty(false)
true
Hey, this is good! Something consistent we can use. Or is it?
> _.isEmpty(true)
true
Sad panda.
finally:
And of course: https://www.destroyallsoftware.com/talks/wat