Tuesday, March 5, 2013

Beware of JavaScript ghosts

Yesterday I was ambushed by a JavaScript ghost. Or conned? Not sure. Does not matter. I am just confused. Here's what happened. My function (an event handler) is passed an object:
function(result) {... 
Inside the function I can programmatically examine the object just fine. For instance I can retrieve the values of the object properties.
function(result) { 
    var s = result.status;
}
I can also introduce a variable and assign the object to be its value:
function(result) { 
    var s = result.status;
    var r = result;
}
Once it is done, I can access the property value off the object reference I assigned to the variable:
function(result) { 
    var s = result.status;
    var r = result;
    s = r.status;
}
So what exactly is the problem, the ambush, the con? Here... The same expression(r.status;) executed outside the function gives a different result. Instead of let us say 500 you will get undefined. More than that, if you examine the value of r itself, while inside it shows up as an object passed as the argument, once outside it becomes undefined.

The variable looses its value as it is passed out of scope!!!

You do not believe this is possible? I would not either, but do not take my word for it. Check for yourself.

Ok, Ok... I cheated - just a little. This is not just any object - this is an XHR returned by JQuery for an error. Also JavaScript it is not, not completely. As you can see in the fiddle, the failing expression is not a JavaScript expression but rather an angular expression. They just look the same and I would expect them to work the same way. Confusing...

2 comments:

  1. Okay, I've made some research on this, not complete of course.  Actually it looks like the AngularJS expression parser cannot evaluate the XMLHttpRequest object reference passed through the $scope.  Moreover, it cannot evaluate that reference on any depth, not only at the first level.  See here for details.

    But.

    I have two remarks here.  First one is that there is no need to pass such a heavy object like XMLHttpRequest to the view level.  I think it is better to pass only needed properties through the wrapper object.

    The second thing is that it is much better to use "Angular way", I mean use AngularJS $http service instead of jQuery.ajax().  You'll never get that XMLHttpRequest issue with AngularJS $http service.

    ReplyDelete
  2. On the last point I totally agree. Unfortunately $http service as of now does not support uploading files

    ReplyDelete