MacPython Logo from __future__ import *

Kailash and Friends Kailash Kher Kaipa

online mp3 Anoice albums buy Amund Maarud albums online Asia online CD Andy M. Stewart buy tracks Axis online Astral Rising A Beautiful Machine download CD Aereda buy tracks Aksent online tracks Absidia Atrium Carceri A Beautiful Machine Absolum buy CD Aryan Wind and Brumalis and Valhalla Saints online music Atomsmasher download albums AK1200 download music Angelzoom online CD Arturo Mantovani and his Orchestra buy music 16 buy tracks Ashtorath online CD Aimee Mann buy music Anael And Bradfield buy mp3 Autumnblaze download mp3 Aggrolites download CD Arj Snoek buy albums Ada buy CD Aalto Andy With Rama West A Beautiful Machine Absolum online tracks Asura albums online Albert Lee 4 Non Blondes A Beautiful Machine Absolum download albums Andrew Lloyd Webber and Ar Rahman online music African Head Charge download mp3 Amber Asylum online music Analena online music ANTIX feat ROB SALMON A.R. Rahman A Beautiful Machine Absolum online tracks African Blackwood buy mp3 Axis buy mp3 Alan Menken buy music Amoebic Dysentery buy Alph Secakuku A Beautiful Machine albums download Albita online Amparo Ochoa A Beautiful Machine download tracks Andy Partridge and Harold Budd download tracks Anubian Lights Alient Project A Beautiful Machine Absolum buy albums Antonio Forcione download CD Ali G Indahouse online mp3 Art and Jazz Messengers Blakey download Arab Strap A Beautiful Machine online albums Adema buy Agua de Annique A Beautiful Machine buy CD Avalanches download tracks Acroma Andi Deris A Beautiful Machine Absolum download tracks American Steel download albums Amanda Perez online 999 A Beautiful Machine download mp3 Arild Andersen download CD American Steel buy tracks Absolute Beginner download tracks Anubi online albums Ancient Wisdom online A Verse Unsung A Beautiful Machine buy music Aghast Andromeda Island A Beautiful Machine Absolum download Arlo Guthrie A Beautiful Machine online mp3 Aavepyora online albums Achillea buy Andrew Bird A Beautiful Machine buy music Alexey Aigui and Ensemble 4'33'' albums buy Abbey Lincoln and Archie Shepp download albums Archive download CD A Guy Called Gerald feat. D.S. download music Al Di Meola online music Abigail download music Angel Witch online music Adelaide

2005-06-02

JavaScript sucks (volume 1)

Filed under: AJAX, debugging, javascript — bob @ 5:17 pm

JavaScript Sucks:

  1. You can extend types by assigning stuff to their prototype, but that can easily break code since these new things can show up when iterating over the properties of an instance. There is no way to hide these new properties. Only magical built-in prototypes can define hidden properties.
  2. Arrays are braindead because you can't trust the built-in ways to compare them. Strangely enough it seems that == is broken in most implementations, but the other comparison operators seem to do the right thing. However, that is observed behavior, and I don't trust it to do the same thing everywhere.
  3. The only built-in mapping is the object, which means all keys must be strings.
  4. Everything is an object, except for the three or forty things that aren't. Ugh.
  5. Referencing names of things that don't exist is not an error, but returns undefined. Referencing a property of undefined is an error. It's a great way to get an exception very, very, far away from the code that was broken.
  6. Some implementations don't like extraneous commas, so you can't sanely write multi-line literal objects or arrays. When you have them, you'll get strange errors and it will take you a long time to find and fix them.
  7. There's no way to introspect the stack beyond the function that's currently running, and the function that called it. Your test failed, somewhere. Debugging JavaScript sucks.
  8. Exceptions raised by "C code" often carry no information about the last JavaScript line that was running (if you were especially fortunate, it would simply crash the browser, in IE's case anyway). Finding where an error happened basically requires a binary search of the new code that you introduced with debugging statements until you find it.
  9. Unit tests are good, the JavaScript unit test frameworks available aren't. The fact that exceptions are so hard to track down makes unit tests basically necessary in order to remain sane, why the hell isn't there something as good as py.test? There's a port of Perl's TestSimple, which is usable, but there's plenty of things not to like about it right now (which is to be expected, at 0.03).
  10. There's no operator overloading.
  11. There's no sprintf (to format numbers, mostly).
  12. Generally, there are a lot of objects that behave like arrays, but aren't, so you either have to convert them to arrays or not expect to be able to use array methods everywhere. Fortunately, there isn't a quick and easy way to convert an array-like object to a real array. Awesome.
  13. No varargs syntax, but you can call functions with variable arguments and painfully extract additional arguments from the arguments local variable. So, it's kinda like Perl subs, except since arguments isn't a real array, you can't even shift off the arguments or otherwise use it as a regular array. Ugh.
  14. foo.bar() and var bar = foo.bar; bar(); do entirely different things. You can write a function that does return a "bound function", but then you have this: var bar = bind(foo.bar, foo);. Dumb!

continued...

25 Comments »

  1. Whoa, I’ve never had such severe problems with JavaScript errors. What does it? FWIW, I’ve had pretty good luck with either Visual Studio or MS Script Debugger w/ IE. They’ve even tracked down errors in scripts that were called in via a chain of document.writes.

    Comment by Robert Sayre — 2005-06-02 @ 5:57 pm

  2. The DOM support in IE 6 is where I found the worst behavior. In one case, it crashed the browser on removeChildNode (which was perfectly valid and worked everywhere else). In other cases, it would throw exceptions with no useful error message (just a randomish number) and no stack trace (I think that was on a getAttribute)… so I have to wrap it in try {} because IE is dumb.

    Comment by Bob Ippolito — 2005-06-02 @ 6:11 pm

  3. Can you elaborate just a bit on items #2, #4, and #12? Thanks.

    Comment by Chris Ryland — 2005-06-02 @ 6:39 pm

  4. Can you elaborate just a bit on items #2, #4, and #12? Thanks.

    Everything is an object, except for the three or forty things that aren’t. Ugh.

    Items 4 and 12 are related: the special arguments variable isn’t an Array in some browsers. This means that the standard Array methods, such as .push, aren’t available. The ’simplest’ method to convert it into one is to do something like: var a = []; for (i = 0; i < arguments.length; i++) a.push(arguments[i]); . Definitely a PITA.

    Comment by Mark Rowe — 2005-06-02 @ 7:02 pm

  5. #2.
    Pop open Firefox, open the JavaScript Console, and type the expression: [] == []
    Any arrays will suffice, but the answer is false. So, you can’t use the built-in equality operator to compare arrays, and there is no built-in equality method for arrays (or anything else), so you have to write your own. Even if they fix this in the future, you still have to care about current browser stupidity.

    #4.
    undefined is not an object, numbers are not objects, strings are not objects, booleans are not objects, and functions are not objects (all according to typeof, anyway). Everything else is supposed to be an object, but a lot of the built-in additions that you’ll find (i.e. DOM support) only sort-of behave like objects.

    #12.
    All of the DOM collection objects (e.g. Node.childNodes), the arguments special local variable, and other sequences of stuff aren’t instances of Array. So, while they support the length property and can be indexed like an array, they don’t have any of the other methods that arrays do (slice, etc.). Arrays do not have a constructor that copies the contents of another array, nor is there a built-in “extend”, and the addition operator for arrays doesn’t work with these array-like objects.. so you have to write your own function that iterates over an array-like and creates a real array with it (or implements the Array method you needed as a function).

    Comment by Bob Ippolito — 2005-06-02 @ 7:04 pm

  6. Incidentally jsolait has an implementation of sprintf in it. I like a few of the idioms in prototype as well, which kind of help to avoid or mitigate some of these issues.

    For the DOM weirdness, I just happened to be reading this article on JS performance, and it talks about NodeLists, which are… interesting. I guess it’s a problem of having “live” lists, and it’s not just the lack of array methods that make such lists obnoxious, they also perform in very odd ways.

    Comment by Ian Bicking — 2005-06-02 @ 9:40 pm

  7. Prototype looks like it can cause more problems than it solves, hacking prototypes and whatnot. I didn’t expect anything else from Ruby guys :) I had actually already written a library with similar functionality (without the bling effects) that was function based rather than class/namespace happy, so it leaves the builtins alone and is probably faster (well, I’m sure it is, but the question is whether it makes a difference). It also looks like they’re working around browser deficiencies in browsers that they don’t even support.. which I find a little strange and distracting.

    I have also seen jsolait and its sprintf, but my point was that the language doesn’t have the feature, not that it’s unimplementable. Currently, I only need “%.2f”, and I already had it written, so I didn’t feel very inclined to bring in a library (one that’s LGPL nonetheless) to remove a few lines of code.

    Comment by Bob Ippolito — 2005-06-02 @ 10:45 pm

  8. Yes, javascript’s deeply broken. What should happen in order for some sort of script to be usable again?

    -A good design to start with, like, you know, python?
    -An independent standard implementation across browsers.
    -An independent standard implementation of the sgml parser that produces one and the same DOM across browsers
    -A rigid specification which api’s a browser must support to call himself compatible.

    Comment by Florian Bösch — 2005-06-03 @ 2:34 am

  9. Javascript is glue.
    Use it as glue, not as a hammer.

    Comment by Glue — 2005-06-03 @ 12:28 pm

  10. JavaScript (in the context of browsers) is not glue, it’s an application development platform. It just happens to suck. As Florian said, it’s deeply broken. However, it’s also the only option for many applications with constraints that make putting all of the logic server-side infeasible.

    Comment by Bob Ippolito — 2005-06-03 @ 12:33 pm

  11. Word. Regarding point 11: If all you need to do is round/truncate a number to a particular number of decimal places, remember you can use yourNumber.toFixed(places).

    I agree with the rest of your points, though, for the most part.

    Comment by Wevah — 2005-06-03 @ 1:09 pm

  12. Number.toFixed() is “%0.2f” (except it rounds rather than truncates). I’m using it, but I’m stripping the padding to make it like “%.2f”… so the functionality is almost there, but it’s not really.

    Comment by Bob Ippolito — 2005-06-03 @ 1:57 pm

  13. Which implementations have you been messing around with?

    At least it’s not VBScript.

    Comment by Joe Grossberg — 2005-06-03 @ 3:25 pm

  14. Well, VBScript is consistently dumb and requires less testing effort ;)

    I guess the worst part of JavaScript is that it’s so close to not sucking, but the language designers and implementors seem to have some brain damage that hasn’t been operated on yet.

    Comment by Bob Ippolito — 2005-06-03 @ 4:01 pm

  15. You know to fix JavaScript for web apps? Use Flash.

    Comment by Tim Beynart — 2005-06-21 @ 12:35 pm

  16. The only real advantage to Flash is that you get most of the same bugs on all platforms they support (which is far fewer than Mozilla). In exchange, you get terrible performance on Everything But Windows, and developing Flash apps on the Mac is really bad too because the IDE is buggy and the important shortcuts conflict with other stuff in the OS. I don’t know what they were smoking.

    ActionScript 1 suffers from almost all of the same problems as JavaScript, plus a few, minus a few others. No real surprise there.
    ActionScript 2 is braindead in entirely different ways. A step forward, but a step and a half backwards.
    … and I hear they’re going to change ActionScript again for Flash 8.

    Flash for mostly text driven web applications with tables and shit just doesn’t work. It’s fine if you want to add a graphing component (or something similarly self-contained), but doing entire pages with it just isn’t feasible for lots of reasons.

    Comment by Bob Ippolito — 2005-06-21 @ 12:46 pm

  17. Generally, there are a lot of objects that behave like arrays, but aren’t, so you either have to convert them to arrays or not expect to be able to use array methods everywhere. Fortunately, there isn’t a quick and easy way to convert an array-like object to a real array. Awesome.

    You can, however, do something like Array.push.call( arraylike, somevalue );. Except when you can’t – not all implementations seem to support it, or support it consistently. It works as expected in SpiderMonkey and Rhino, though.

    Comment by Aristotle Pagaltzis — 2005-07-23 @ 3:25 pm

  18. You mean Array.prototype.push.call(arrayLike, someValue). Sure, whatever. You’re right, it doesn’t work everywhere, which makes it useless trivia.

    Comment by Bob Ippolito — 2005-07-23 @ 3:43 pm

  19. Interesting post/rant, although I think there are some things that you are confused about.

    First, arrays aren’t really braindead, neither are objects. When given at least one object as an operand, the equality operator (==) checks to see if the two objects are the same. So []==[] returns false, but var a = []; a==a; returns true. That’s not dumb, it’s the same way Java works. The only difference is that most Java objects have an equals() method that will determine if two objects are logically equal as opposed to being actually equal.

    Second, there are specific things to know about objects. The typeof operator isn’t entirely accurate. However, there are both primitive and reference versions of booleans, numbers, and strings:

    var b1 = true;
    var b2 = new Boolean(true);
    var n1 = 1;
    var n2 = new Number(1);
    var s1 = "string";
    var s2 = new String("string");
    alert(typeof b1); //boolean
    alert(typeof b2); //object
    alert(typeof n1); //number
    alert(typeof n2); //object
    alert(typeof s1); //string
    alert(typeof s2); //object

    All primitive values for boolean, number, and string have the same properties and methods as the reference values except that they can’t be dynamically extended.

    In regards to point #5, referencing variables that don’t exist return undefined only if you don’t try to use it. If you try to use an undefined variable in, for example, a mathematical operation, you’ll get an error.

    In regards to point #7, check out the JavaScript debugger for Mozilla.

    Point 12 is correct, though this is the same as most other languages I know that have collections, arrays, arraylists that work sort of the same but not entirely (I’m looking at you, .NET).

    For #13, it sucks but it works. It’s easy enough to use a for loop to iterate through the arguments.

    Point 14: you say dumb, I say powerful. The ability to take a function and have it seemlessly work as a method of any other object is powerful. Yes, it requires a little extra thought, but that doesn’t make it dumb.

    Comment by Nicholas — 2005-08-09 @ 9:06 pm

  20. I’m not confused, but I am coming from an other-agile-languages perspective, not a C#/Java perspective. From your perspective, the features that JavaScript has are powerful… from this mountain, they appear to be braindead.

    I don’t agree with a single one of your points.

    First, arrays aren’t really braindead, neither are objects. When given at least one object as an operand, the equality operator (==) checks to see if the two objects are the same. So []==[] returns false, but var a = []; a==a; returns true. That’s not dumb, it’s the same way Java works. The only difference is that most Java objects have an equals() method that will determine if two objects are logically equal as opposed to being actually equal.

    Yes, that is braindead. For some objects == is logical equality, and other objects it is reference identity. That is stupid. It should be logical eqality everywhere, and there should be another operator for identity. Or, there should be a built-in scheme for determining logical equality between two objects, in JavaScript you must roll your own for everything (which I did in MochiKit).

    Second, there are specific things to know about objects. The typeof operator isn’t entirely accurate. However, there are both primitive and reference versions of booleans, numbers, and strings:

    I am aware of that, but nobody uses the reference versions of primitives because they’re worthless. Next!

    In regards to point #5, referencing variables that don’t exist return undefined only if you don’t try to use it. If you try to use an undefined variable in, for example, a mathematical operation, you’ll get an error.

    No, you’ll get NaN.

    In regards to point #7, check out the JavaScript debugger for Mozilla.

    I have, and it’s poorly implemented. Rarely helpful at all.

    Point 12 is correct, though this is the same as most other languages I know that have collections, arrays, arraylists that work sort of the same but not entirely (I’m looking at you, .NET).

    However, most languages have the concept of an iterator, which makes this mostly moot.

    For #13, it sucks but it works. It’s easy enough to use a for loop to iterate through the arguments.

    Easy enough, but not powerful enough.

    Point 14: you say dumb, I say powerful. The ability to take a function and have it seemlessly work as a method of any other object is powerful. Yes, it requires a little extra thought, but that doesn’t make it dumb.

    It is dumb. All of the other agile languages I’m familiar with pass instance methods bound, but provide a way to unbind them. 99% of the time you want bound methods. For the times you don’t, you can get an unbound version and put it on the object. It is *especially* dumb that foo.bar() and bar=foo.bar; bar(); are different syntaxes but look almost identical.

    Comment by Bob Ippolito — 2005-08-09 @ 10:02 pm

  21. Yes, that is braindead. For some objects == is logical equality, and other objects it is reference identity. That is stupid. It should be logical eqality everywhere, and there should be another operator for identity. Or, there should be a built-in scheme for determining logical equality between two objects, in JavaScript you must roll your own for everything (which I did in MochiKit).

    Actually, for all objects it is reference identity, for all primitives it is logical equality. If you want to do reference identitiy all the time, then you should use ===.

    I am aware of that, but nobody uses the reference versions of primitives because they’re worthless. Next!

    You’re very quick to dismiss this. How do you know nobody uses them? They, in fact, have a great deal of value for extending the basic types, among other things.

    No, you’ll get NaN.

    Incorrect. Try this: alert (a + 1);. You’ll get an undefined error. I believe you’re referring to the case when a variable has been declared but not given a value.

    I have, and it’s poorly implemented. Rarely helpful at all.

    I’d love to see what your ideal debugger is. For such a complicated language as JavaScript, Venkman does a very good job.

    However, most languages have the concept of an iterator, which makes this mostly moot.

    You only need an iterator when there are different ways of accessing array/collection items sequentially. Though there are different types in JavaScript, they can all have their items accessed using the same bracket notation, therefore an iterator is of little or no use.

    Easy enough, but not powerful enough.

    What else is needed?

    It is *especially* dumb that foo.bar() and bar=foo.bar; bar(); are different syntaxes but look almost identical.

    It only looks the same because of the variable names you use. Plus, if bar() could function outside of the realm of an object, this would work as you would expect, such as: var a= Math.abs; alert(a(-1));

    Comment by Nicholas — 2005-08-10 @ 11:24 am

  22. a few choice things i noticed today - “//” is the single-line comment delimiter, but forward slashes also delimit regular expressions, when not constructed using RegExp explicitly - so dont expect “”.match(//) to work (why would you?), because the interpreter thinks you’re stating a comment. concordantly, new RegExp(”").toString() == “/(?:)/”, so as not futher the confusion. also, i hoped that [1,2,3] + [4,5,6] would do the sane thing, but no, [1,2,3] + [4,5,6] actually results in “1,2,34,5,6″. like that is what anybody anywhere ever wanted to happen when they added two arrays together.

    Comment by Moe Aboulkheir — 2006-01-06 @ 8:21 pm

  23. Speaking of #12 I found this (I think) nifty library code:
    function object2String(obj){
    var val, output = “”;
    if(obj)
    {
    output += “{”;
    for (var i in obj) {
    val = obj[i];
    switch (typeof val) {
    case (”object”):
    if (val[0]) {
    output += i + “:” + array2String(val) + “,”;
    } else {
    output += i + “:” + object2String(val) + “,”;
    }
    break;
    case (”string”):
    output += i + “:’” + escape(val) + “‘,”;
    break;
    default:
    output += i + “:” + val + “,”;
    }
    }
    output = output.substring(0, output.length-1) + “}”;
    }
    return output;
    }

    function array2String(array) {
    var output = “”;
    if (array) {
    output += “[";
    for (var i in array) {
    val = array[i];
    switch (typeof val) {
    case (”object”):
    if(val[0]) {
    output += array2String(val) + “,”;
    } else {
    output += object2String(val) + “,”;
    }
    break;
    case (”string”):
    output += “‘” escape(val) + “‘,”;
    break;
    default:
    output += val + “,”;
    }
    }
    output = output.substring(0, output.length-1) + “]”;
    }
    return output;
    }

    function string2Object(string) {
    eval(”var result = ” + string);
    return result;
    }

    function string2Array(string) {
    eval(”var result = ” + string);
    return result;
    }
    Besides that;
    I don’t like Venkman (and it’s the best one I have found) - why is it so hard to develope an IDE with a good Intellisense, debug-step-through and local variables? In Venkman(0.9.87) I more often than not loose the page I’m stepping through and I never got watches to work. I total agree with Bob.

    Comment by mega — 2006-04-28 @ 8:59 am

  24. Javascript suck too, but it’s coool with it’s suckity :)
    what i wanted to say?
    may be it’s not a real language, but i do real thing with it :)
    i love it :0

    Comment by you suck — 2006-05-25 @ 6:42 am

  25. I agree with every point, one by one.

    I may also add, in no particular order:

    26. Automagic string number conversion (which is ALWAYS a bad idea), without even having a separate operator for addition and concatenation, woo! The way +, ==, and company work makes me want to end my life.
    27. The retarded existence of undefined, null, NaN and Infinity: we only needed one of these.
    28. The retarded treatment of undefined, null, booleans, numbers and strings: the interpreter will halt miserably if you attempt to access some of these objec- uh… kinds of values’ :( properties, yet some do behave like objects, well, except that in won’t work, and so on.
    29. typeof NaN; 1/-0; NaN == NaN; and others. Try them, you’re in for a good laugh.
    30. Numbers instead of integers and floats, which will make everything slow and probably break one thing or two, starting from the lack of integer division.
    31. Semicolons are optional, well, sometimes anyways, and braces being for either blocks or objects cause some problems.
    32. for iterates over an array’s positions???
    33. Empty regexes can’t be written as // because oops, that starts a comment.

    Ugh. There’s at least 10 more things that suck I can think of, but I’m too tired and disgusted to write them.

    Comment by Miguel Perez — 2007-09-26 @ 8:11 am

RSS feed for comments on this post.

Leave a comment

Protected by WP-Hashcash.

Powered by WordPress