Well, the [spec](http://es5.github.com/#x15.4.4.14) says it all:
> `indexOf` compares `searchElement` to the elements of the array, in ascending order, using the internal *Strict Equality Comparison Algorithm*

The [strict equality comparison algorithm](http://es5.github.com/#x11.9.6) is what happens when you do `a === b`. So, as you can know from es5-shims, you can implement `indexOf` roughly like this:

    for ( var i = 0; i < arr.length; i++ ) {
        if ( arr[i] === target ) {
            return i;

But let's look at the underlying theme which brought your question: Primitives vs. objects. That's an interesting topic in javascript, because everything's an object, except what isn't an object, which is then a primitive. So let's define what a primitive value is, and then we can say that everything else is an object.

A [primitive value](http://es5.github.com/#x4.3.2) is defined very neatly in the spec itself, and says: Something that's either number, string, boolean, null or undefined. `7` is a primitive. `'abc'` is a primitive. `undefined` is a primitive.

Handling primitives is simple: The number 7 is always equal to the number 7. The string `'abc'` is always equal to the string `'abc'`. They are purely mechanical evaluations, and intuitive ones at that, so dwelling on them any longer is a waste of time and space.

So there - now, everything which isn't a number, string, boolean, null or undefined is an object! Simple, right?

Not so simple, because we know that's not completely true - `new String( 'abc' )` gives you an object, and not a primitive. So wassup with that?

It turns out that having things like strings remain primitive rather sucks. If they were just primitives, and not objects, you wouldn't be able to do things like `'abc'.toUpperCase()`, because primitives aren't objects.

Enter wrappers. They are objects designed to literally wrap around primitive values and make them useful. They are `String`, `Number` and `Boolean` (note that undefined and null don't have object representatives.)