10

I was following a tutorial that suggested to check if an object is string and not empty as the following:

var s = "text here";
if ( s && s.charAt && s.charAt(0))

it is said that if s is string then it has a method charAt and then the last component will check if the string is empty or not.

I tried to test it with the other available methods like ( typeof and instanceof ) using some of the SO questions and here and here too !!

so I decided to test it in Js Bin : jsbin code here as follow:

var string1 = "text here";
var string2 = "";


alert("string1  is " + typeof string1);
alert("string2  is " + typeof string2);


//part1- this will succeed and show it is string
if(string1 && string1.charAt){
  alert( "part1- string1 is string");
}else{
  alert("part1- string1 is not string ");
}


//part2- this will show that it is not string
if(string2 && string2.charAt ){
  alert( "part2- string2 is string");
}else{
  alert("part2- string2 is not string ");
}



//part3 a - this also fails !!
if(string2 instanceof String){  
  alert("part3a- string2 is really a string");
}else{
  alert("part3a- failed instanceof check !!");
}

//part3 b- this also fails !!
//i tested to write the String with small 's' => string
// but then no alert will excute !!
if(string2 instanceof string){  
  alert("part3b- string2 is really a string");
}else{
  alert("part3b- failed instanceof check !!");
}

Now my questions are :

1- why does the check for string fails when the string is empty using the string2.charAt ???

2- why does the instanceof check failed??

Community
  • 1
  • 1
stackunderflow
  • 3,811
  • 5
  • 31
  • 43
  • `if(string2.charAt)` is only checking if method is defined, an empty string is still a string so will return true – charlietfl Jul 19 '14 at 19:21
  • @charlietfl plz refere to answer of adeneo where he said "A simple string is not an object, it's a primary data type, and has no prototype, as opposed to a String object created with new String." – stackunderflow Jul 19 '14 at 20:34
  • So empty string defind as literal will not return true if checked for the charAt function presence – stackunderflow Jul 19 '14 at 20:36
  • @stackunderflow It would, if using the code provided. (Because `"".charAt(0) -> "" -> false-y`. The thing that would *not* work is `"" instanceof String && ..`, because it is a *string* value, not a *String* object. – user2864740 Jul 19 '14 at 20:36
  • @user2864740 string created like this (var s ="";) will not have a `cahrAt` function at all !! – stackunderflow Jul 19 '14 at 20:40
  • @stackunderflow Sure it will [have a `charAt` method] - *try it*. This is because a *string* will be promoted to a *String* when a method is invoked upon it. – user2864740 Jul 19 '14 at 20:41
  • @user2864740 cool info regarding (string promotion) thanks buddy – stackunderflow Jul 19 '14 at 20:44
  • 1
    @stackunderflow following your logic you could never do `'somestring'.charAt(n)` – charlietfl Jul 19 '14 at 21:21
  • @charlietfl you are right. but that was misonception corrected by user2864740, when he said that string literals will be promoted to String object. – stackunderflow Jul 19 '14 at 23:57

2 Answers2

14

string values are not String objects (which is why the instanceof fails)2.

To cover both cases using "type-checking" it would be typeof x === "string" || x instanceof String; the first only matches strings and the latter matches Strings.

The tutorial assumes that [only] String objects - or string values which are promoted1 - have a charAt method and so uses "duck-typing". If the method does exist, then it is called. If charAt is used out-of-bounds then an empty string "", which is a false-y value, is returned.

The tutorial code would also accept a string of "\0", while s && s.length would not - but it would also "work" on arrays (or jQuery objects, etc). Personally, I trust the caller to provide the allowed values/types and use as little "type-checking" or special-casing as possible.


1 For primitive values of string, number, and boolean there is a corresponding object type of String, Number, and Boolean, respectively. When x.property is used on one of these primitive values the effect is ToObject(x).property - hence the "promotion". This is discussed in ES5: 9.9 - ToObject.

Neither the null or undefined values have corresponding objects (or methods). Functions are already objects but have a historically different, and useful, typeof result.

2 See ES5: 8 - Types for the different types of values. The String Type, eg., represents a string value.

user2864740
  • 60,010
  • 15
  • 145
  • 220
7

1- Why does the check for string fails when the string is empty using the string2.charAt?

The following expression evaluates to false because the first condition fails:

var string2 = "";
if (string2 && string2.charAt) { console.log("doesn't output"); }

That second line is basically equivalent to:

if (false && true) { console.log("doesn't output"); }

So for example:

if (string2) { console.log("this doesn't output since string2 == false"); }
if (string2.charAt) { console.log('this outputs'); }

2- Why does the instanceof check fail?

This fails because, in javascript, string can be literals or objects. For example:

var myString = new String("asdf");
myString instanceof String; // true

However:

var myLiteralString = "asdf";
myLiteralString instanceof String; // false

You can reliably tell if it's a string by checking both the type and the instanceof:

str instanceof String || typeof str === "string";
David Sherret
  • 101,669
  • 28
  • 188
  • 178
  • you missed something . my question was not putting parameter zero . it is actually without brackets. `if(string1 && string1.charAt){` – stackunderflow Jul 19 '14 at 19:30