spot a subtle JS error here..

The other day I ran into weird errors while editing the Y!Mail patch in browser.js. The whole thing stopped working, and it took me a while to see the problem. Can you see it?

// need to fake someMethod
Element.prototype.someMethod=function(){
    // faking someMethod here
}
// we also have an insertBefore problem so let's fix that too
(function(oF){
    // tweaking insertBefore here
})(Element.prototype.insertBefore);

What was wrong? Hats off if you can see it without running the code.. 🙂

18 thoughts on “spot a subtle JS error here..

  1. I believe it's lacking a semicolon after the first anonymous function declaration.No, I was wrong, linebreak should save that.

  2. You're basically right. (AFAIK in your 1.1.1 above is wrong because the "insertBefore" function isn't run at this point but simply passed as an argument to the someMethod function).It took me a while to understand this issue – sort of masked by all the lines of comments between the blocks, and by the fact that in many of the redefined functions I'm just passing arguments on to the real function without knowing what they are so it was very non-obvious where to start looking in the big Y!Mail scripts when a function that expected an HTML element received a function object ;)Shows why optional semi-colons maybe wasn't a good idea – they become really weird bugs in the few cases where they aren't in fact optional after all..

  3. Or to put it simplier (I hope)…The 2nd function is being passed as an argument to the first because of the parenthesis and lack of semi-colon. Removing the parenthesis or adding the semi-colon should fix it.

  4. Just to expand so my thinking is clearer to others that might read this, the interpreter will compute the result as follows:1. Element.prototype.someMethod is to be filled, to know with what, we must compute the next statement.1.1 function(){ faking someMethod here } is being returned as an object, but it is followed by a parenthesis, indicating we want to call that function right away.1.1.1 In order to compute the parameter, we must compute what function(Element.prototype.insertBefore){tweaking insertBefore here} returns, which is null1.2 We can now find what function(){faking sometMethod) returns by giving it the parameter 'null' – which it ignores and returns null.2. Element.prototype.someMethod is now null

  5. AHA! Wait a second, it is related to the semicolon!What will happen is that Element.prototype.someMethod will contain what was returned from function(){ something } with the argument to that being the result from the second anynomous declaration.Correct? 🙂

  6. hallvors (and cwolves): You're right about 1.1.1 being wrong, testing it reveals that the entire function object is being passed as a parameter. I just figured that it would go on forever as long as there were more parenthesis'. Good job finding this doozy! I'm learning so much from all this, please keep posting :-)However, next time we meet I'm going to demand that you tip your hat at me as promised ;-P

  7. RobbieGee – What's actually happening is that the 2nd function is getting passed as a parameter to the 1st. The next set of parenthesis (Element.prototype.insertBefore) is being passed as a parameter to the result of the first function. Since the first function doesn't return a function itself, you should get an error. And actually if the 2nd set of parenthesis wasn't there, the problem would have probably never been noticed.x=function(a){ return function(b){ alert(a+b); }}(a=5)(b=6);Also note that this only happens because you're assigning the first function to a variable. If the first function was just a function (wasn't a prototype), this wouldn't happen.

  8. insertBefore is declared in Node, not Element :)I came up with the exact same problem when making my syntax highlighter script. Now to avoid problems I ALWAYS place semicolons where there can be one.

  9. Bonus points to xErath for noticing a second bug – just typing in the demo for the sake of the post, I knew I should have copied and pasted it ;-)feldgendler: simply to make it easier for beginners. It is in fact quite a lot easier to get things working when the browser forgives you for forgetting a semi-colon – in theory it is a great feature for a newbie-gentle scripting language.

  10. If semicolons were strictly required, a missing semicolon would be a bug which can be spotted at the very first run. In reality, a missing semicolon in an obscure place like this is a bug which can take hours to locate.

  11. Although I've never encountered this before in my own code, I amazingly enough just ran into it, only what, a week after your post? Took me about a second to recognize, thanks to this discussion :-)Number.prototype.NaN0=function(){return isNaN(this)?0:this;}(function classNamespace(){ var C = function() {…:-)

  12. Does the ECMAScript spec define how to handle such ambiguities? I didn't dive so deeply into the spec.

    It's not an ambiguity. Removing uneeded white-space revals

    function(...){
      ...
    }( ... )

    So you're clearly declaring a function, and calling it at the same time.It's a matter of perspicacity.

  13. expression (expression)can be interpreted either as a function call or as two statements between which a semicolon has been omitted. Here is the amiguity.

  14. Hallvors. You should be an idol ;)Double-click "perspicacity" in xErath's post, rightclick highlighted text, choose "Dictionary" and you're done 😛

Leave a reply to cwolves Cancel reply