Search code examples
javascriptgwttypesjsni

Javascript instanceof & typeof in GWT (JSNI)


I've encountered an curious problem while trying to use some objects through JSNI in GWT. Let's say we have javscript file with the function defined:

test.js:

function test(arg){
  var type = typeof(arg);
  if (arg instanceof Array)
    alert('Array');
  if (arg instanceof Object)
    alert('Object');
  if (arg instanceof String)
    alert('String');
}

And the we want to call this function user JSNI:

public static native void testx()/ *-{
  $wnd.test( new Array(1, 2, 3) );
  $wnd.test( [ 1, 2, 3 ] );
  $wnd.test( {val:1} );
  $wnd.test( new String("Some text") );
}-*/;

The questions are:

  • why instanceof instructions will always return false?
  • why typeof will always return "object" ?
  • how to pass these objects so that they were recognized properly?

Solution

  • instanceof shouldn't be returning false all the time in your example unless you're testing objects from a different window, because an array from one window is not an instance of the Array constructor of a different window.

    Using instanceof is great when you need to test for a specific thing and you're operating within one window (you do have to be aware of the string primitive vs. String object thing that scunliffe pointed out). Note that you need to be careful of your order, since an array is an instanceof Object (as well as Array); this applies to Strings and all other objects as well.

    There's an alternative that doesn't have the window issue and which can readily be used for switch statements and the like if you're doing dispatch:

    function classify(arg) {
        return Object.prototype.toString.call(arg);
    }
    

    That looks odd, but what it does is use the toString function on the Object prototype, which has a defined behavior (rather than using any override that the actual object you're testing may have, which may have different behavior). So given this function:

    function show(arg) {
        alert(classify(arg));
    }
    

    you'll get these results:

    show({});               // [object Object]
    show("a");              // [object String]
    show(new String("a"));  // [object String]
    show([]);               // [object Array]
    show(/n/);              // [object RegExp]
    show(function() { });   // [object Function]
    

    and you'll get those results regardless of what window the object you're testing is coming from and regardless of whether you use a string primitive or a String instance.