If we try to call the hello() method we defined in our component implementation, we get:

> comp.hello();
TypeError on line 1: comp.hello is not a function

This happens because, as we mentioned earlier, comp is not the HelloWorld JS object itself, but an XPConnect wrapper around it:

> dump(comp);
[xpconnect wrapped nsISupports]

The idea of these wrappers is to make the JavaScript-implemented XPCOM components look just like any other XPCOM component to the user. This also makes the public interface of the component clearer and provides protection for the component's internal data.

Calling QueryInterface on the wrapper works, because it is defined in the nsISupports interface, and the wrapper knows the underlying object implements nsISupports:

As you can see, the QueryInterface call also made the wrapper know about the other interface our component supports. Assuming the nsIHelloWorld interface defines the hello method, we can now call it:

> comp.hello()
Hello World!

While this behavior is nice for production code as it forces you to clearly define the interfaces that should be used to access the component, it's inconvenient to write the interfaces (and recompile each time you change them) when working on a prototype of the component.

Meet wrappedJSObject

XPConnect lets you bypass its wrappers and access the underlying JS object directly using the wrapper.wrappedJSObject property if the wrapped object allows this.