Julian Jelfs’ Blog

Scope shenanigans part three

Posted in Javascript by julianjelfs on January 24, 2010

So in my previous posts here and here I described a problem I was having with Microsoft Ajax script library serialisation of Dates that had been created in a different scope to that where the serialisation is actually taking place. I also described a somewhat hacky solution that involves iterating through the data to be serialised, tagging dates and then switching scope and recreating the dates in the new scope.

This works fine, but I don’t like the idea of having to recreate all these dates all the time so I go to thinking a bit more about what (someDate instanceof Date) actually means. Roughly it means, was this date created with the Date function. Given that I wandered if the following two statements were equivalent:

var date = new Date();
alert(date instanceof Date);    //true
alert(date.constructor === Date);    //true

If so then perhaps I can do the following:

var dateA = top.frames["frameB"].date;
alert(dateA instanceof Date);    //false
dateA.constructor = Date;    //change the constructor function
alert(dateA instanceof Date);    //true

If so, I can avoid having to recreate the Date objects, I can just reassign their constructor functions. Sadly, it doesn’t work. It seems that there is more to instanceof than just checking the constructor function. So we still have to be wary of using instanceof, but remember that the original problem was with the Microsoft Ajax script serialisation so all is not lost. The MS code detects type like this:

Type.prototype.isInstanceOfType = function Type$isInstanceOfType(instance) {    
    var e = Function._validateParams(arguments, [{name: "instance", mayBeNull: true}]);    
    if (e) throw e;    
    if (typeof(instance) === "undefined" || instance === null) return false;    
    if (instance instanceof this) return true;    
    var instanceType = Object.getType(instance);    
    return !!(instanceType === this) ||           
        (instanceType.inheritsFrom && instanceType.inheritsFrom(this)) ||           
        (instanceType.implementsInterface && instanceType.implementsInterface(this));
}

So it uses instanceof first, but if that returns false, it goes on to call Object.getType which looks like this:

Object.getType = function Object$getType(instance) {    
    var e = Function._validateParams(arguments, [{name: "instance"}]);    
    if (e) throw e;    
    var ctor = instance.constructor;    
    if (!ctor || (typeof(ctor) !== "function") || !ctor.__typeName || (ctor.__typeName === 'Object')) {        
        return Object;    
    }    
    return ctor;
}

Which is basically just returning the object’s constructor property. So by overwriting the constructor argument as described, although instanceof still cannot be trusted, Date.isInstanceOfType(object) as defined in the Microsoft Ajax script library will work as expected and therefore so will MS javascript serialisation.

The upshot is that by overwriting the date object’s constructor property with the Date function from the required scope we can get Date.isInstanceOfType(object) to return true and there is no need to completely recreate the date in the required scope. If, however, you want instanceof to work – the only way I can achieve that is to recreate the date. If anyone knows of a better way, I’d love to hear it.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: