What's the point of new String("x") in JavaScript?

26,784

Solution 1

There's very little practical use for String objects as created by new String("foo"). The only advantage a String object has over a primitive string value is that as an object it can store properties:

var str = "foo";
str.prop = "bar";
alert(str.prop); // undefined

var str = new String("foo");
str.prop = "bar";
alert(str.prop); // "bar"

If you're unsure of what values can be passed to your code then I would suggest you have larger problems in your project. No native JavaScript object, major library or DOM method that returns a string will return a String object rather than a string value. However, if you want to be absolutely sure you have a string value rather than a String object, you can convert it as follows:

var str = new String("foo");
str = "" + str;

If the value you're checking could be any object, your options are as follows:

  1. Don't worry about String objects and just use typeof. This would be my recommendation.

    typeof str == "string".

  2. Use instanceof as well as typeof. This usually works but has the disadvantage of returning a false negative for a String object created in another window.

    typeof str == "string" || str instanceof String

  3. Use duck typing. Check for the existence of one or more String-specific methods, such as substring() or toLowerCase(). This is clearly imprecise, since it will return a false positive for an object that happens to have a method with the name you're checking, but it will be good enough in most cases.

    typeof str == "string" || typeof str.substring == "function"

Solution 2

Javascript creators created wrappers for basic types like string or int just to make it similar to java. Unfortunately, if someome makes new String("x") the type of the element will be "object" and not "string".

var j = new String("x");
j === "x"  //false
j == "x" //true

Solution 3

String objects can have properties, while string primitives can not:

var aStringObject=new String("I'm a String object");
var aStringPrimitive="I'm a string primitive";

aStringObject.foo="bar";
console.log(aStringObject.foo); //--> bar

aStringPrimitive.foo="bar";
console.log(aStringPrimitive.foo); //--> undefined

And String objects can be inherited from, while string primitives can not:

var foo=Object.create(aStringObject);
var bar=Object.create(aStringPrimitive); //--> throws a TypeError

String objects are can only be equal to themselves, not other String objects with the same value, while primitives with the same value are considered equal:

var aStringObject=new String("I'm a String object");
var anotherStringObject=new String("I'm a String object");

console.log(aStringObject==anotherStringObject); //--> false

var aStringPrimitive="I'm a string primitive";
var anotherStringPrimitive="I'm a string primitive";

console.log(aStringPrimitive==anotherStringPrimitive); //--> true

You could implement overloading-like behavior:

function overloadedLikeFunction(anArgument){
    if(anArgument instanceof String){
        //do something with a String object
    }
    else if(typeof anArgument=="string"){
        //do something with a string primitive
    }
}

Or specify argument purpose:

function aConstructorWithOptionalArugments(){
    this.stringObjectProperty=new String("Default stringObjectProperty value");
    this.stringPrimitiveProperty="Default stringPrimitiveProperty value";
    for(var argument==0;argument<arguments.length;argument++){
        if(arguments[argument] instanceof String)
            this.stringObjectProperty=arguments[argument];
        if(typeof arguments[argument]=="string")
            this.stringPrimitiveProperty=arguments[argument];
    }
}

Or track objects:

var defaultStringValue=new String("default value");
var stringValue=defaultStringValue;

var input=document.getElementById("textinput") //assumes there is an text <input> element with id equal to "textinput"
input.value=defaultStringValue;
input.onkeypress=function(){
    stringValue=new String(this.value);
}

function hasInputValueChanged(){
    //Returns true even if the user has entered "default value" in the <input>
    return stringValue!=defaultStringValue;
}

The existence of String objects and string primitives effectively gives you two string "types" in Javascript with different behaviors and, consequently, uses. This goes for Boolean and Number objects and their respective primitives too.

Beware, however, of passing string (or other) primitives as the value of this when using the function methods bind(), call() and apply(), as the value will be converted to a String object (or a Boolean or a Number object, depending on the primitive) before being used as this:

function logTypeofThis(){
    console.log(typeof this);
}

var aStringPrimitive="I'm a string primitive";
var alsoLogTypeofThis=logTypeofThis.bind(aStringPrimitive);

console.log(typeof aStringPrimitive); //--> string;
logTypeofThis.call(aStringPrimitive); //--> object;
logTypeofThis.apply(aStringPrimitive); //--> object;
alsoLogTypeofThis(); //--> object;

And unexpected/counter-intuitive return types:

var aStringObject=new String("I'm a String object");
console.log(typeof aStringObject); //--> object
aStringObject=aStringObject.toUpperCase();
console.log(typeof aStringObject); //--> string

Solution 4

You could use instanceof if you really want to be paranoid:

if(typeof x === "string" || x instanceof String)

The instanceof operator will properly handle subclasses of String too:

obj instanceof ConstructorFunction works by checking if ConstructorFunction.prototype is in the prototype chain of obj.

I don't think I've ever actually used the String class in JavaScript but there's nothing wrong with being paranoid and aiming for correctness.

Solution 5

In most cases you work alone and can control yourself, or on a team and there is a team guideline, or can see the code you're working with, so it shouldn't be a problem. But you can always be extra safe:

var obj = new String("something");
typeof obj; // "object"

obj = ""+obj;
typeof obj; // "string"

Update

Haven't though much about the implications of this, although it seems to work:

var obj = new String("something"), obj2 = "something else";
obj.constructor === String; // true
obj2.constructor === String; // true

Of course, you should check if the object has a constructor (i.e. if it is an object).

So you could have:

isString(obj) {
   return typeof obj === "string" || typeof obj === "object" && obj.constructor === String;
}

Although I suggest you just use typeof and "string", a user should know to pass through a normal string literal.

I should note this method is probably susceptible to someone creating an object and setting it's constructor to be String (which would indeed be completely obscure), even though it isn't a string...

Share:
26,784
Pacerier
Author by

Pacerier

# 9

Updated on July 09, 2022

Comments

  • Pacerier
    Pacerier almost 2 years

    What are the use cases for doing new String("already a string")?

    What's the whole point of it?

  • Pacerier
    Pacerier about 13 years
    so what's the best way to check if a variable is string?
  • Pacerier
    Pacerier about 13 years
    im creating a class which takes a parameter in its constructor. but this parameter is supplied by the user. the constructor will do something if the parameter is a string and will do something else if the parameter is not a string so i was wondering is there a way i could determine if the parameter is a string (supplied by the user). i couldn't use str = "" + str because i can't assume that the parameter will be only either a "true" string or a string object.. it may be some other object
  • Tim Down
    Tim Down about 13 years
    @Pacerier: "this parameter is supplied by the user" - how is it provided? Who is the user? I really wouldn't worry about this, but I'll update my answer with the options.
  • mu is too short
    mu is too short about 13 years
    Just checking the constructor property isn't quite enough. There could strange people out there that subclass String in JavaScript.
  • davin
    davin about 13 years
    @mu is too short, yeh you have a point, although I thought about instanceof it looks like the OP was just trying to differentiate between an object, a string literal and new String('blah'). Whatever, the idea is out there, we can nitpick all day.
  • mu is too short
    mu is too short about 13 years
    I just figure that you should go half way with pedantry, if you're going to be pedantic then go all the way :)
  • rhigdon
    rhigdon about 11 years
    The first sentence says it all.
  • ssss
    ssss almost 10 years
    str = "" + str; converts everything to a string. If you only want to convert String objects to strings (and Number objects to numbers, etc.), but otherwise leave things alone, you can write str = str.valueOf().
  • Tek
    Tek almost 10 years
    I really like this answer.
  • mjs
    mjs almost 7 years
    console.log(new String('abc')) doesn't output anything, why??