String, called as a function, converts its argument to a string. String, called as a constructor, creates an object whose prototype is the String function. (Check James's Answer for the relevant ECMAScript specification section.)
This is indeed confusing.
The two equality operators actually do very different things. From the ECMA-262, v 5.1 document, === does:
- If Type(x)is different fromType(y), returnfalse.
- If Type(x)isUndefined, returntrue.
- If Type(x)isNull, returntrue.
- If Type(x)isNumber, then
 a. IfxisNaN, returnfalse.
 b. IfyisNaN, returnfalse.
 c. Ifxis the sameNumbervalue asy, returntrue.
 d. Ifxis+0andyis-0, returntrue.
 e. Ifxis-0andyis+0, returntrue.
 f. Returnfalse.
- If Type(x)isString, then returntrueifxandyare exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, returnfalse.
- If Type(x)isBoolean, returntrueifxandyare bothtrueor bothfalse; otherwise, returnfalse.
- Return trueifxandyrefer to the same object. Otherwise, returnfalse.
Whereas == does:
- If Type(x)is the same asType(y), then
 a. IfType(x)isUndefined, returntrue.
 b. IfType(x)isNull, returntrue.
 c. IfType(x)isNumber, then
 i. IfxisNaN, returnfalse.
 ii. IfyisNaN, returnfalse.
 iii. Ifxis the sameNumbervalue asy, returntrue.
 iv. Ifxis+0andyis-0, returntrue.
 v. Ifxis-0andyis+0, returntrue.
 vi. Returnfalse.
 d. IfType(x)isString, then returntrueifxandyare exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, returnfalse.
 e. IfType(x)isBoolean, returntrueifxandyare bothtrueor bothfalse. Otherwise, returnfalse.
 f. Returntrueifxandyrefer to the same object. Otherwise, returnfalse.
- If xis null andyis undefined, returntrue.
- If xis undefined andyis null, returntrue.
- If Type(x)isNumberandType(y)isString, return the result of the comparison
 x == ToNumber(y).
- If Type(x)isStringandType(y)isNumber, return the result of the comparison
 ToNumber(x) == y.
- If Type(x)isBoolean, return the result of the comparisonToNumber(x) == y.
- If Type(y)isBoolean, return the result of the comparisonx == ToNumber(y).
- If Type(x)is eitherStringorNumberandType(y)isObject, return the result of the comparisonx == ToPrimitive(y).
- If Type(x)isObjectandType(y)is eitherStringorNumber, return the result of the comparisonToPrimitive(x) == y.
- Return false.
Note that in the spec, the Type of a primitive string object is String, whereas the type of any object (including the String object) is Object.
With === the relevant line is #1: the Type of the objects are different, so false is returned.
With == the relevant line is #8: x is a String ("Hello world!") and y is an Object (The String object containing the string "Hello world!"). Thus the comparison x == ToPrimitive(y) is made. ToPrimitive ends up calling the valueOf method of the object, or if that method doesn't exist, the toString method. In this case, a String object's valueOf method returns the primitive string the object contains. Thus the equality operation is done again, this time between two primitive strings which contain the same text, which returns true thanks to #1.d.
JavaScript is a bit messy under the hood...
EDIT: Notice that if two objects are compared, no conversions apply, but rather, rule #1.f applies. Thus, thanks to the spec, I was able to correctly predict the output of the following code:
> new String("hi") == new String("hi")
false
EDIT: Just thought I'd add that these distinctions are even further blurred by more implicit type conversion. For example, the following works:
> ("hi").toString()
"hi"
but that's not because "hi" is an object (like in Python):
> typeof "hi"
"string"
But rather, because the . operator does a conversion from the primitive string type to the string Object type (creating a new string object) whose toString method is then called.