Casting to string in JavaScript - javascript

I found three ways to cast a variable to String in JavaScript.
I searched for those three options in the jQuery source code, and they are all in use.
I would like to know if there are any differences between them:
value.toString()
String(value)
value + ""
DEMO
They all produce the same output, but does one of them better than the others?
I would say the + "" has an advantage that it saves some characters, but that's not that big advantage, anything else?

They do behave differently when the value is null.
null.toString() throws an error - Cannot call method 'toString' of null
String(null) returns - "null"
null + "" also returns - "null"
Very similar behaviour happens if value is undefined (see jbabey's answer).
Other than that, there is a negligible performance difference, which, unless you're using them in huge loops, isn't worth worrying about.

There are differences, but they are probably not relevant to your question. For example, the toString prototype does not exist on undefined variables, but you can cast undefined to a string using the other two methods:
​var foo;
​var myString1 = String(foo); // "undefined" as a string
var myString2 = foo + ''; // "undefined" as a string
var myString3 = foo.toString(); // throws an exception
http://jsfiddle.net/f8YwA/

They behave the same but toString also provides a way to convert a number binary, octal, or hexadecimal strings:
Example:
var a = (50274).toString(16) // "c462"
var b = (76).toString(8) // "114"
var c = (7623).toString(36) // "5vr"
var d = (100).toString(2) // "1100100"

In addition to all the above, one should note that, for a defined value v:
String(v) calls v.toString()
'' + v calls v.valueOf() prior to any other type cast
So we could do something like:
var mixin = {
valueOf: function () { return false },
toString: function () { return 'true' }
};
mixin === false; // false
mixin == false; // true
'' + mixin; // "false"
String(mixin) // "true"
Tested in FF 34.0 and Node 0.10

According to this JSPerf test, they differ in speed. But unless you're going to use them in huge amounts, any of them should perform fine.
For completeness: As asawyer already mentioned, you can also use the .toString() method.

if you are ok with null, undefined, NaN, 0, and false all casting to '' then (s ? s+'' : '') is faster.
see http://jsperf.com/cast-to-string/8
note - there are significant differences across browsers at this time.

Real world example: I've got a log function that can be called with an arbitrary number of parameters: log("foo is {} and bar is {}", param1, param2). If a DEBUG flag is set to true, the brackets get replaced by the given parameters and the string is passed to console.log(msg). Parameters can and will be Strings, Numbers and whatever may be returned by JSON / AJAX calls, maybe even null.
arguments[i].toString() is not an option, because of possible null values (see Connell Watkins answer)
JSLint will complain about arguments[i] + "". This may or may not influence a decision on what to use. Some folks strictly adhere to JSLint.
In some browsers, concatenating empty strings is a little faster than using string function or string constructor (see JSPerf test in Sammys S. answer). In Opera 12 and Firefox 19, concatenating empty strings is rediculously faster (95% in Firefox 19) - or at least JSPerf says so.

On this page you can test the performance of each method yourself :)
http://jsperf.com/cast-to-string/2
here, on all machines and browsers, ' "" + str ' is the fastest one, (String)str is the slowest

Related

JavaScript: Difference between toString and toString()

I'm struggling to understand this JavaScript behaviour (javascript n00b alert!!!). Source of the question is a typo in my code which led to the undesired situation. What I wanted to know is the length of a certain number. For example, if its 100, then answer should be 3, if 5893 then answer should be 4 and so on. To achieve this what I did simply is convert number to a string and then invoke .length on the string.
private getNumberLength(num: number) {
return num.toString().length;
}
In the above return statement, I had typo such that it looked like
return num.toString.length;
The result was no compilation error and getNumberLength always returned 1. I fail to understand this (why 1?). Can somebody please help me understand this?
Below you can quickly test if you wish
var num = 666;
console.log('Length on toString(): ' + num.toString().length);
console.log('Length on toString: ' + num.toString.length);
Looks like this is Javascript behavior of automatically boxing primitive values to its Object counterpart to call its method.
The function looks correct, but to answer your question (I don't understand the downvotes).
toString is a reference to the function. The reason why toString.length works is because as quoted from Mozilla.
Function.length = The length property indicates the number of parameters expected by the function.
So if you redeclare your function as
private getNumberLength(num: number, num2: number) {
return num.toString().length;
}
getNumberLength.length will return 2.
toString.length will return 1 as it only expects one parameter.
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length
toString() is invoking the function toString (and getting its return value). This is performing the actual conversion to String.
All the best with Javascript

SyntaxError when extending Number object

I am trying to extend the Number object with this code:
Number.prototype.isNumber = function(i){
if(arguments.length === 1){
return !isNaN(parseFloat(i)) && isFinite(i);
} else {
return !isNaN(parseFloat(this)) && isFinite(this);
}
}
try {
var x = 8.isNumber();
} catch(err) {
console.log(err);
}
I get SyntaxError: identifier starts immediately after numeric literal
also when I try the following:
Number.isNumber(8)
I get Number.isNumber is not a function!!
The JavaScript parser reads 8.isNumber as a number literal.
To access a Number method on a numeric literal you'll have to surround the number with parenthesis so the JavaScript interpreter knows you're trying to use the number properties.
Number.prototype.isNumber = function(i) {
if (arguments.length === 1) {
return !isNaN(parseFloat(i)) && isFinite(i);
}
return !isNaN(parseFloat(this)) && isFinite(this);
}
try {
var x = (8).isNumber();
console.log(x);
} catch(err) {
console.log(err);
}
I couldn't help it but provide an additional answer although you already accepted one.
The first thing you need to know, is that there is a fundamental difference between the Number object, and the Number prototype (see here).
As it stands, you are extending the Number prototype, not the object itself! Your isNumber implementation actually has the same effect like the following:
Number.prototype.isNumber = function(){return isFinite(this)}
Why? Because in order to execute this prototype method, the parser first needs to know the type of the literal you are invoking the function on. That's why you either need to turn your number literal into an expression by wrapping it in parentheses: (8).isNumber() or by using an even weirder notation 8..isNumber() (the first . is the decimal point, the second the property accessor). At this point, the javascript engine already evaluated it as a Number and thus can execute the isNumber() method.
On the other hand, although at first glimpse your code looks like it could handle the following case correctly (since you are doing a parseFloat): "8".isNumber() will always throw an exception, because here we have a string literal, and the String prototype does not have the according method. This means, you will never be able to detect numbers that are actually string literals in the first place.
What you instead should do, is directly extend the Number object so you can actually do a proper check without having to deal with errors:
Number.isFiniteNumber = function(i){
return !Number.isNaN(i) && Number.isFinite(i);
}
Number.isFiniteNumber(8); // returns true
Number.isFiniteNumber("3.141"); // returns true
Number.isFiniteNumber(".2e-34"); // returns true
Number.isFiniteNumber(Infinity); // returns false
// just for informational purposes
typeof Infinity === "number" // is true
Bonus material:
Extending native objects is potentially dangerous.
Number.isNaN() probably does not what you think it does.

var x; ... x.trim(); Why sometimes it allows but sometimes it makes the rest of the code stop working?

This minor issue causes me 5 hours to fix. Finally I figured out. See this code:
<script language="JavaScript" type="text/javascript">
var x;
.... // a lot of codes here
var k=x.trim();
</script>
The above code made the whole app stop working!
I remembered that I used to do like that before but got no problem.
So, about var x; ... x.trim();, Why sometimes it allows but sometimes it makes the rest of the code stop working?
And what is the best code practice for it?
You can do like this:
if(typeof x === 'undefined'){
// your get an error message
}
else
{
var k=x.toString().trim();
}
Using strict equality operator === above is good idea there because in JS, you can name a variable as undefined too:
var undefined = "something";
So using === makes sure that you are really checking against undefined value for a variable.
trim is a function of String. Refer MDN - String.trim().
So when you apply it to an integer, it fails and throws error, causing you code to stop work
Example
try{
var a = 1;
console.log(a.trim());
}
catch(ex){
console.log(ex);
}
You can try to convert number to string using .toString() and then apply .trim()
try{
var a = 1;
console.log(a.toString().trim());
}
catch(ex){
console.log(ex);
}
I would expand Rajesh's answer. He's right, when you try to call a method that does not exist, a TypeError is thrown. The easiest and fool-proof approach would be to use try/catch to ensure that the rest of the code would be executed as it should. But it's likely that even if it does, you don't get the result you want.
I believe the best way to do would be to wrap the value you're having into String object. It's as easy as
var k = String(x).trim();
It does several important things:
Converts the value of x, whatever it be, into a string, i.e. when you check its type, it's always 'string' and is always an instance of the String object.
Ensures that the resulting value has the method trim which does what it should.
Doesn't throw any error, so the rest of the code is executed.
There may be several pitfalls. If x is undefined, null, NaN or an object, the result of String(x) would be, correspondingly, 'undefined', 'null', 'NaN', or '[object Object]'. If x is an array, it's a specific case, and the value would be the same as if you call x.join(','), for example
x = [1, 2, 3];
var k = String(x).trim; // k is now '1,2,3'
So always keep in mind what types you're dealing with.
Just as with String, you can cast variables to other types, but naïvely converting anything into a Number, a String or an Array is considered a very bad practice. You should always be somewhat sure what type you're working with.

Set a number return value for an object

I've previously asked a fairly similar question, and with this answer, I know it's possible to make objects that return strings when placed inside other strings. This would be some code based on that answer which would allow the object to have a custom string return value:
function myString(value) {
this.String = value;
}
myString.prototype.toString = function() {
return this.String;
}
var strObj = new myString('Foo');
//>> strObj
//<< myString {String: "Foo", toString: function}
//>> strObj+''
//<< "Foo"
//What I want in addition to this:
//>> +strObj
//<< 42
I originally got the idea for that original question by seeing the effects of Date objects within strings. So, since there's another feature of Date objects that could be quite useful, I'd like to know if there's a way for me to do the same thing as Date objects do when used in an expression (being converted to a number):
+new Date(); //1401414068943
I'd like my myString object to do the same. I've tried to continue the mindset of the prototype toString in the object, but although there is a JS method to convert to strings, there's no method - only a native function - to convert non-numbers to strings.
So is it possible for me to do this 'automatic object-to-number conversion' for my own objects, or is this some kind of sorcery only available to Date because it's native to JS?
I'd like the syntax to then be
var strObj = new myString('Foo', 42);
if that's possible.
I believe the prototype method you are looking for that handles object to numeric conversion is Object.prototype.valueOf()
It can be altered or customized just as you are altering toString()
Be aware that this sort of thing can be considered bad style when it may confuse other programmers (including yourself at a future date) as standard conversions can be redefined to behave differently than expected.
toString is the method that is invoked when an object is used in a string context (more exactly, when ToString is called on it). And yes, there is a similar method that is invoked when an objet is used in a numeric context (ToNumber): valueOf. If either doesn't exist, the other is used, for details see the DefaultValue algorithm.
function MyHybrid(str, num) {
this.string = str;
this.value = num;
}
MyHybrid.prototype.toString = function() {
return this.string;
};
MyHybrid.prototype.valueOf = function() {
return this.value;
};
var hybrid = new MyHybrid('Foo', 42)
String(hybrid) // "Foo"
Number(hybrid) // 42
However, it must be noted that strObj+'', which you have used for a conversion into a string, does not call ToString. The + operator can both act on numbers and strings, and therefore does only call ToPrimitive without a type hint - in which case valueOf is preferred (unless it is a Date object). hybrid+'' is equivalent to 42+'' and will yield "42".

Is it incorrect to use eval() within this function? Can I accomplish the same functionality without it somehow?

I'm trying to write a function I can use to test all for falsy values, keeping it concise since it will be run quite often serverside.
function is_falsy(val){
val = eval(String(val).toLowerCase());
return !!val;
}
I wonder if there's any way it could be done shorter, or what the possible negative implications of using eval() might be. JSBIN tells me it is "evil".
JSBIN
Assuming that val is a string that represents a JavaScript literal then we can take advantage of the fact that the only false-y values in JavaScript are:
0 (+ or -)
NaN
the empty string ('') or ("")
null
undefined
false
Thus, ignoring edge-cases (like 0.0) we could write it like so (a lower case can be performed as in the original code):
function is_falsey_literal (lit) {
if (['""', "''", "null", "undefined", "false", "0", "NaN"].indexOf(lit) >= 0) {
return true;
}
// Ideally there are more checks on numeric literals such as `-0` or `0.0`.
return false;
}
If needing to check a full expression then eval may "work" and is likely more practical when compared to writing a full JavaScript-in-JavaScript parser. For instance, in the above, the input string of (void 0) will be "true" although it evaluates to undefined which is definitely not a truth-y value.
Of course, perhaps the original data can be written/consumed such that there is no need for such a construct at all ..
There should never be any need to treat a string containing false or undefined as falsy. Doing so is inviting false positives (or false negatives) on possibly completely unrelated data.
Imagine what else would be treated as "falsy":
!true
!1
!!true
it's begging for mysterious bugs in your application further down the line.
The program flow should make sure that an undefined value actually arrives at your testing script as a literal undefined, not a string "undefined".
If you only want to test is falsy, then the below is enough.
function is_falsy(val){
return !val;
}
If you want to test whether a string is falsy value like 'false', then
function is_falsy(val){
try {
return !JSON.parse(String(val).toLowerCase());
} catch(e) {
return false;
}
}

Categories