Unexpected results in JavaScript - javascript

Using the node.js console, I get the following unexpected results:
> 2 + "3"
"23"
> 2 * "3"
6
Why does the first example favor string concatenation and integer multiplication in the second example? I would not expect concatenation between different types, but rather an error to be thrown. If this is the behavior in JS, how can I predict the type of the final result?

In JavaScript the + operator serves as both addition and concatenation (joining two strings together) and will default to concatenation when one of the two values is a string.
Since you are using it between an integer and a string it will default to concatentation. If you ever need to force the addition operation you will need to make sure all of your values are numbers. You can do this with parseInt() and parseFloat() functions.
2 + parseInt("3"); // 5
The * operator is for multiplication only and as such it will automatically cast strings to numbers to perform the operation.
Given the above there's another trick you can use to force string numbers to actually become numbers which is multiplying them by 1 *1.
2 + "3"*1; // 5

According to ECMAScript 2015 Language Specification (Addition operator, Multiplicative operators), the evaluation of additive expression is (lprim is the left primitive (lval converted to primitive), rprim is the right one):
...
If Type(lprim) is String or Type(rprim) is String, then
Let lstr be ToString(lprim).
ReturnIfAbrupt(lstr).
Let rstr be ToString(rprim).
ReturnIfAbrupt(rstr).
Return the String that is the result of concatenating lstr and rstr.
Let lnum be ToNumber(lprim).
ReturnIfAbrupt(lnum).
Let rnum be ToNumber(rprim).
ReturnIfAbrupt(rnum).
Return the result of applying the addition operation to lnum and rnum.
The evaluation of multiplicative expression is:
...
Let lnum be ToNumber(leftValue).
ReturnIfAbrupt(lnum).
Let rnum be ToNumber(rightValue).
ReturnIfAbrupt(rnum).
Return the result of applying the MultiplicativeOperator
You can see that if it is an additive expression, it is first to check whether there is a String. If there is a String, string concatenation is executed. Otherwise, the values are converted to Number and an addition operation is executed.
If it is a multiplicative expression, it would always convert values to Number and deliver a multiplicative operation.

Related

How a string(like "123") is converting to a number if I add + before it but not after it?

When I add a + before a number in quotes like +"123", it is converting to typeof number but if I add like "123"+, it is waiting for next operands. Why? Why in the first case it is converting to a number?
In the first case, you use an Unary plus +
The unary plus operator precedes its operand and evaluates to its operand but attempts to convert it into a number, if it isn't already. Although unary negation (-) also can convert non-numbers, unary plus is the fastest and preferred way of converting something into a number, because it does not perform any other operations on the number. It can convert string representations of integers and floats, as well as the non-string values true, false, and null. Integers in both decimal and hexadecimal ("0x"-prefixed) formats are supported. Negative numbers are supported (though not for hex). If it cannot parse a particular value, it will evaluate to NaN.
in the second you are using just an Addition
The addition operator produces the sum of numeric operands or string concatenation.
As you have + and - symbols(as unary operators) to numbers prepended only not appended. In the same way, when you add some + or - to strings, same applies and are if able to convert to numbers they will be converted to numbers. But when you append that, it is treated as binary operator. So, concatenates.
+"123" can be parsed as the unary + operator followed by the String 123. As you can see in the spec, the job of the unary + operator specifically is to cast its operand to a Number type.
"123"+ can't be parsed as a valid JS expression, because the + token should always be followed by an operand, whether it is to be parsed as the unary + operator or the binary + addition operator.
You can understand it by reading this article https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
Unary operator. Attempts to convert the operand to a number, if it is
not alread

Why is number + string a string in javascript?

Sort of trying out some quirks in javascript:
First I did
console.log("5" + 1);
This prints 51, this is normal right, both number and string have a + operator, but since string is the first variable it will convert 1 to a string.
Now when I did this:
console.log(1 + "5")
I expected output to be 6, as I thought it would convert string to a number.
However, the magic output was 15.
Could anyone more experienced in javascript brighten this up for me?
Quoting ECMAScript spec The Addition operator ( + ) section:
If Type(lprim) is String or Type(rprim) is String, then
Return the String that is the result of concatenating ToString(lprim) followed by ToString(rprim)
So the order doesn't matter here.
console.log(1 + "5")
I expected output to be 6, as I thought it would convert string to a number. ...
But then what would you expect if you had written the following?
console.log(1 + " fine day")
or
console.log(1 + " answer(s) to my question")
There can be no assurance as a general rule that a string is convertible to a number. But any number can be converted to a string. That's why the conversion rules are written to move toward a type that is compatible. (In contexts where you as a programmer know that a string can be safely converted to a number, then you can do so explicitly so that the + operation is between two numbers. But that is not true in general for strings.)
In other contexts, this is also why small ints and low precision floats would be converted to large ints or double precision floats when operating on mixed types that the latter types. You can safely convert the limited forms into the larger forms, but you cannot safely go in the other direction in general. A small int can be represented as a big int or a double, but the other direction is not generally a safe conversion.
So conversion rules for operation on mixed types are written as much as is feasible to move toward mutually compatible types that are safe common types. It is left to the programmer to write explicit conversions for the special cases where a more general type can be safely converted to a more limited type.
In both cases the value will be converted to a string.
When you add a number to a string or a string to a number, the result is a string.
Simply use parseInt(value) or toString(value) to force the conversion.
You can try code :
console.log(1 + parseInt("5"))
=> 6
Concatenation also uses + in Javascript.
var result = "String" + number + obj;
// is equivalent to
string result = "String" + number.ToString() + obj.ToString();
However thing is, in C# / .net you could do the same thing, and you will get the same result - System.Console.WriteLine("result is " + 10 + 20);.
In JavaScript (and C# for that matter) strings are immutable. They can never be changed, only replaced with other strings. You're probably aware that combined + "String" doesn't directly modify the combined variable - the operation creates a new string that is the result of concatenating the two strings together, but you must then assign that new string to the combined variable if you want it to be changed.
The argument about using mathematical operators to do string concatenation is arguably an "incorrect" argument, but there's also an argument to be made that using + to do a lot of string concatenation can be very slow.

Bitwise operations on strings in javascript

In javascript the following test of character to character binary operations prints 0 676 times:
var s = 'abcdefghijklmnopqrstuvwxyz';
var i, j;
for(i=0; i<s.length;i++){ for(j=0; j<s.length;j++){ console.log(s[i] | s[j]) }};
If js was using the actual binary representation of the strings I would expect some non-zero values here.
Similarly, testing binary operations on strings and integers, the following print 26 255s and 0s, respectively. (255 was chosen because it is 11111111 in binary).
var s = 'abcdefghijklmnopqrstuvwxyz';
var i; for(i=0; i<s.length;i++){ console.log(s[i] | 255) }
var i; for(i=0; i<s.length;i++){ console.log(s[i] & 255) }
What is javascript doing here? It seems like javascript is casting any string to false before binary operations.
Notes
If you try this in python, it throws an error:
>>> s = 'abcdefghijklmnopqrstuvwxyz'
>>> [c1 | c2 for c2 in s for c1 in s]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'str' and 'str'
But stuff like this seems to work in php.
In JavaScript, when a string is used with a binary operator it is first converted to a number. Relevant portions of the ECMAScript spec are shown below to explain how this works.
Bitwise operators:
The production A : A # B, where # is one of the bitwise operators in the productions above, is evaluated as follows:
Let lref be the result of evaluating A.
Let lval be GetValue(lref).
Let rref be the result of evaluating B.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToInt32(rval).
Return the result of applying the bitwise operator # to lnum and rnum. The result is a signed 32 bit integer.
ToInt32:
The abstract operation ToInt32 converts its argument to one of 232 integer values in the range −231 through 231−1, inclusive. This abstract operation functions as follows:
Let number be the result of calling ToNumber on the input argument.
If number is NaN, +0, −0, +∞, or −∞, return +0.
Let posInt be sign(number) * floor(abs(number)).
Let int32bit be posInt modulo 232; that is, a finite integer value k of Number type with positive sign and less than 232 in magnitude such that the mathematical difference of posInt and k is mathematically an integer multiple of 232.
If int32bit is greater than or equal to 231, return int32bit − 232, otherwise return int32bit.
The internal ToNumber function will return NaN for any string that cannot be parsed as a number, and ToInt32(NaN) will give 0. So in your code example all of the bitwise operators with letters as the operands will evaluate to 0 | 0, which explains why only 0 is printed.
Note that something like '7' | '8' will evaluate to 7 | 8 because in this case the strings used as the operands can be successfully convered to a number.
As for why the behavior in Python is different, there isn't really any implicit type conversion in Python so an error is expected for any type that doesn't implement the binary operators (by using __or__, __and__, etc.), and strings do not implement those binary operators.
Perl does something completely different, bitwise operators are implemented for strings and it will essentially perform the bitwise operator for the corresponding bytes from each string.
If you want to use JavaScript and get the same result as Perl, you will need to first convert the characters to their code points using str.charCodeAt, perform the bitwise operator on the resulting integers, and then use String.fromCodePoint to convert the resulting numeric values into characters.
I'd be surprised if JavaScript worked at all with bitwise operations on non-numerical strings and produced anything meaningful. I'd imagine that because any bitwise operator in JavaScript converts its operand into a 32 bit integer, that it would simply turn all non-numerical strings into 0.
I'd use...
"a".charCodeAt(0) & 0xFF
That produces 97, the ASCII code for "a", which is correct, given it's masked off with a byte with all bits set.
Try to remember that because things work nicely in other languages, it isn't always the case in JavaScript. We're talking about a language conceived and implemented in a very short amount of time.
JavaScript is using type coercion which allows it to attempt to parse the strings as numbers automatically when you try to perform a numeric operation on them. The parsed value is either 0 or more likely NaN. This obviously won't get you the information you're trying to get.
I think what you're looking for is charCodeAt which will allow you to get the numeric Unicode value for a character in a string and the possibly the complementary fromCodePoint which converts the numeric value back to a character.

When to use parseInt

Which rule do I have to follow when extracting numbers out of DOM and calcluation with them? How does javascript knows that a value is a number or not? Should I always use parseInt?
Given following Code:
HTML
<div id="myvalue">5</div>
<div id="withParseInt"></div>
<div id="withoutParseInt"></div>
<div id="withoutParseIntButIncrement"></div>
JS & jQuery:
var value = $('#myvalue').text();
$('#withParseInt').text(parseInt(value) + 1);
$('#withoutParseInt').text(value + 1);
$('#withoutParseIntButIncrement').text(value++);
Gives following output:
5
6
51
5
Fiddle: http://jsfiddle.net/ytxKU/3/
The .text() method will always return a string. Some operators, like the + operator, are overloaded to perform both arithmetic and string operations. In the case of strings, it performs concatenation, hence the "51" result.
If you have a string and need to use a non-coercing operator, you will have to use parseInt (or some other method of converting to a number).
However, the * operator for example implicity performs this coercion, so you wouldn't need the parseInt call in that situation (see an updated fiddle for example).
Note that the increment ++ operator does coerce its operand, but you've used the postfix operator so it won't have any effect. Use the prefix operator and you can see it working:
$('#withoutParseIntButIncrement').text(++value);
So, to summarise:
// Parses string to number and adds 1
$('#withParseInt').text(parseInt(value) + 1);
// Coerces number 1 to string "1" and concatenates
$('#withoutParseInt').text(value + 1);
// Implicity coerces string to number, but after it's been inserted into the DOM
$('#withoutParseIntButIncrement').text(value++);
// Implicity coerces string to number, before it's been inserted into the DOM
$('#withoutParseIntButIncrement').text(++value);
// Implicity coerces to number
$('#withoutParseIntButMultiply').text(value * 2);
Side note: it's considered good practice to always pass the second argument (the radix) to parseInt. This ensures the number is parsed in the correct base:
parseInt(value, 10); // For base 10
One and only rule:
Every value that you retrieve from the DOM is a string.
Yes, you should always use parseInt() or Number() to be on the safe side. Otherwise Javascript will decide what to do with it
The value itself is a string
Using operator + will concatenate two strings
Using operator - will calculate the numerical difference
...
It's always good to use parseInt just to be on the safe side, especially as you can supply a second parameter for the numerical system to use.
By the way, in your final example it should be ++value if you want it to equal 6.

How come JavaScript converts to a string when adding a string and a number?

Why is it that this code evaluates to:
10 + "10" => "1010"
"10" + 10 => "1010"
and why does it not work like this:
10 + "10" => 20 // the number comes first
"10" + 10 => "1010" // the string comes first
EDIT:
More specifically, where in the implementation of the interpreter does it do this? Or, how does it do this?
The ECMAScript 262 Specification codifies the JavaScript language (JavaScript is actually the Mozilla implementation of ECMAScript). In any case, things are relatively easy to find in Annotated ES5 which I usually consult.
See 11.6.1 The Addition operator ( + ):
The addition operator either performs string concatenation or numeric addition.
The production AdditiveExpression : AdditiveExpression + MultiplicativeExpression is evaluated as follows:
Let lref be the result of evaluating AdditiveExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating MultiplicativeExpression.
Let rval be GetValue(rref).
Let lprim be ToPrimitive(lval).
Let rprim be ToPrimitive(rval).
If Type(lprim) is String or Type(rprim) is String, then
Return the String that is the result of concatenating ToString(lprim) followed by ToString(rprim)
Return the result of applying the addition operation to ToNumber(lprim) and ToNumber(rprim). See the Note below 11.6.3.
+ is a concatenation operator and as well as arithmetic operator in Javascript. If it finds that operator is used between string and number then it concatenates that number into string else if you using operator for two integers then result will also be integer.
So,
STRING + STRING = STRING
STRING + INTEGER = STRING
INTEGER + STRING = STRING
INTEGER + INTEGER = INTEGER
When comparing values that have different types, JavaScript uses a complicated and confusing set of rules. In general, it just tries to convert one of the values to the type of the other value (as we can see in your question). This is often noted as automatic type conversion.
Let's take a look at your code:
10 + "10" => "1010"
"10" + 10 => "1010"
In JavaScript, if any non-string value is added to a string, the value is automatically converted to a string before it is concatenated. Thus JavaScript, regardless of the ordering of your integer or string values, treats any integer as a string.
You should know, however, that JavaScript does not apply this to all arithmetic operators. For example, if we were to multiply our values we would get:
10 * "10" => 100
"10" * 10 => 100
"ten" * 10 => NaN
Now, why does Javascript do this? Well, you could argue it's for convenience sake. There are many instances were you might need to concatenate two values into a string. On the contrary, you can never multiply an integer with a character string, as we can see in the last example above.
unfortunately, this is how Javascript works

Categories

Resources