Javascript typing (Int/String) question - javascript

I have encountered something weird (probably not, it's more likely that I don't really get it) in JavaScript and I'd be curious to find out why things behave like they do.
When I do:
var index = '1';
index++;
alert(index);
index = index + 1;
alert(index);
index = true ? index + 1 : 0;
alert(index);
as in http://jsfiddle.net/5mdmJ/ the alerts will go "2", "3", "4"
When I reverse the order and do this (http://jsfiddle.net/5mdmJ/1/):
var index = '1';
index = true ? index + 1 : 0;
alert(index);
index = index + 1;
alert(index);
index++;
alert(index);
I'll have "11", "111" and "112".
I do know that this is something with index being a string, but I don't really get why it's int-typed all the way through in example 1 and string-typed in exampled two.
I know this is probably going to be really simple but I could not find anything by now that really clarifies to me the logic behind what's going on. Does the type change? Why and when does this happen?
Thanks for any hint or article or whatever!

The single plus operator is overloaded for strings and ints.In the first example, the ++ operator is only defined for ints, so index gets converted to a number, then incremented. Afterwards, the plus operator indicates addition. Since index is a string in the second example, the plus operator indicates concatenation.

but I don't really get why it's int-typed all the way through in example 1
Unlike +, which has two meanings (addition for number, concatenation for strings), ++ has no ambiguity - it always means "increment"
So when you run ++ on a string, it converts it into a number. Since this doesn't happen in example #2, the + operations are all concatenations.
var x = '1';
x++;
alert(typeof x); // "number"

The answer is that since js is loosely typed it starts with the first operation that youre performing.
In your example 1 the first operation is an exclusive arithmetic operation and js correctly interprets it and considers it INT all the way
In your example 2 the first operation is an comparsion operation and js interprets it as boolean and then its immediately close property string.
Thats why you get different behaviours.

This: index++; is an number function. Notice that I didn't say integer. There is no such thing as an integer in JavaScript. All numbers are floating point numbers.
This: index = true ? index + 1 : 0; is string concatenation, because index is a string. If index is a number then it would add the two together.
So what is happening is that the ++ operator is converting the string to a number and adding the values. In the second its converting the number to a string and appending the two strings together to form a new string (remember in JavaScript strings are immutable).

The reason is that variable++ will convert the variable first to number and then increase it by one. Whilst variable + 1 will only add 1 to the variable, but not converting it.

It's because of the type priority when you concatenate strings or variables.
"1" + 2 + 3; // -> "123"
4 + 3 + "2"; // -> "72" ; 4 + 3 = 7 ; 7 + "2" = "72"

My GUESS is, that when you do index++, it's considered an "int", and stays that way through example one, but when you do index + 1, it's considered a string, and stays like that through example 2..

Related

Why am I getting a number and not a concatenated string?

I have this code
var n = parseInt(prompt("Give me a number"));
var sum = 0;
for (let i=0; i < n.toString().length; i++){
let expon = n.toString()[i] ** n.toString().length;
sum += expon;
}
My doubt is the following: If my n is 371, n.toString()[0] is '3' (A STRING!!), why is it then that when I do ** n.toString().length (which is 3). I get 27 ?!!?
Also, it is clear to me that if x = '3' and I do x + x I get '33' and not 6. Can this happen to the addition only? why?
'3' ** 3 is 27 because ** converts both its arguments to numbers if possible. It has no function other than numeric exponentiation.
'3' + 3 is '33' because + has multiple possible functions (addition and string concatenation), and if at least one of the arguments is a string, string concatenation is used instead of addition. In another universe, it may well attempt to do numeric addition first and end up at 6, but the language designers of our universe chose to do it this way round.
Check this: https://medium.com/swlh/strings-and-basic-mathematical-operators-in-javascript-e9de3d483dae
In simple words - in JavaScript, when trying to add String type to non-String type, adding operator automatically casts added elementsto both be set of characters, because '+' can be understood as adding OR as concatenating. Although, every different arithmetic operations (substracting, dividing, multiplying, powering, etc.) performed on String and non-String type will force the first one to be casted to the Number form. If not possible, we will receive NaN result.

What does JavaScript interpret `+ +i` as?

An interesting thing I've never seen before was posted in another question. They had something like:
var i = + +1;
They thought the extra + converted it to a string, but they were simply adding to a string which is what caused it to convert.
This, however, lead me to the question: what is going on here?
I would have actually expected that to be a compiler error, but JavaScript (at least in Chrome) is just fine with it... it just basically does nothing.
I created a little JSFiddle to demonstrate: Demo
var i = 5;
var j = + +i;
document.body.innerHTML = i === j ? 'Same' : 'Different';
Anyone know what's actually occurring and what JavaScript is doing with this process?
I thought maybe it would treat it like ++i, but i doesn't increment, and you can even do it with a value (e.g., + +5), which you can't do with ++ (e.g., ++5 is a reference error).
Spacing also doesn't affect it (e.g., + + 1 and + +1 are the same).
My best guess is it's essentially treating them as positive/negative signs and putting them together. It looks like 1 == - -1 and -1 == + -1, but that is just so weird.
Is this just a quirky behavior, or is it documented in a standard somewhere?
Putting your the statement through the AST Explorer, we can see that what we get here is two nested Unary Expressions, with the unary + operator.
It's a unary expression consisting of + and +i, and +i is itself a unary expression consisting of + and i.
The unary expression with the unary + operator, will convert the expression portion into a number. So you're essentially converting i to a number, then converting the result of that to a number, again (which is a no-op).
For the sake of completion, it works on as many levels as you add:
var i = 5;
console.log(+ + + + + +i); // 5
console.log(i); // still 5
It's in the specification.
Digging through, we can see from §14.6.2.2 that the increment and decrement operators are listed before (and should be preferred) over the unary operators. So precedence alone won't explain this.
Looking up the the punctuation table in §11.7, we can see that every single instance of ++ (the operator) in the spec shows the two together, without whitespace. That's not conclusive, until you check...
The whitespace rules in §11.2, specifically:
White space code points may occur within a StringLiteral, a RegularExpressionLiteral, a Template, or a TemplateSubstitutionTail where they are considered significant code points forming part of a literal value. They may also occur within a Comment, but cannot appear within any other kind of token.
JS does not allow arbitrary whitespace mid-operator.
The JS syntax in both PegJS and Esprima corroborate this, matching on the literal two-character string ++.
For me it's very clear;
var a = +3;
var b = +a; // same as a, could be -a, for instance
var c = + +a; // same as above, same as +(+a)
If you do ++variable the javascript interpreter sees it as the increment operator.
If you do + +variable the javascript interpreter sees it as Unary plus, coercing the value to a number, twice.
So
var a = 1;
var b = +a;
var c = +b;
console.log(c);// still 1
is the same as
var c = + +1;
So the simple answer is that two plus signs can not be separated by a space to be interpreted as incrementation, the space makes it so the interpreter sees two seperate spaces, which is what it really is
The + operators converts into a number, two + operators with a space in between does nothing additional.
Even though it might look very similar, + + and ++ are not at all the same thing for an AST interpreter. The same applies to token separation: varfoo is not the same as var foo.
In the expression + + +i, each + is considered as distinct unary operator, which simply convert your variable to a number. For the incrementation operation, which is ++, no spaces are allowed, neither between the + and the variable token. In the example below, the last line is not valid:
var x = "4";
console.log(+ + +x);
console.log(+ + ++x);
console.log(+ ++ +x);

reversing a number in javascript (clarification)

I have a simple question to ask, in which I am slightly embarrassed to ask, but I realize that I won't learn unless I ask.
When looking at reversing a string, I recognize that reversing a string requires you to split up the string, reverse it, and then re-join it. Like so.
var stringReverse = function (n){
return n.split("").reverse().join("");
}
console.log(stringReverse("hello"));
However, I was trying to reverse a number, much of the principles were very similar except for one part. The code below is:
var reverse_a_number = function (n){
n = n + "";
return n.split("").reverse().join("");
}
console.log(reverse_a_number(32243));
My question is why am I needed to bring in the " n = n + " ";" to the code? I was assuming that the same principles would be similar regardless of it being a string, or an integer.
Much thanks in advance, and I apologize that this question is elementary.
why am I needed to bring in the " n = n + " ";" to the code?
Adding + "" will make a cast to String, this way you can use String functions (.split).
The integer have only functionality of a Number. If you want to treat the Number as a String you need to cast it (+ "") or convert it (.toString())
The .reverse() function come from Array object that is created when you use String function .split().
With .join() you come back to String from Array (of characters).
If you want to come back to Number after reverting, you can choose one of these functions.
To put it simply, the docs require it to be a string. You could combine your two methods by doing exactly what you're doing in reverse_a_number (it works for both). Also, don't be embarrassed to ask questions, it's how you learn :)
Number doesn't have reverse and split method directly and you should convert number to string that be able reverse it.
to convert it you can add an empty string after it, like you.
just it.
Javascript sets the type of a variable at runtime.
If she (yes, it's a girl) sees that you only have ciphers, she will consider it's an integer.
Adding + ""; casts it into a string, which is an array of chars.
Your string is stored a lil bit like : ['h', 'e', 'l', 'l', 'o']
an integer is stored as {0011001010101...}
Explanation
You are passing in a number, not a string. When you combine a number with a string ("") it assumes you want to make a string. So you are really converting it to a string. To an array, then back to a string. If you attempt to split a number, the compiler will throw an error. More exactly
TypeError: undefined is not a function (evaluating 'n.split('')')
So what you really are doing is making the number into a String. There are different methods you can use, take a look here.
n += '';(String) ->
.split() (Array) -> .split() (Array) -> .join() (String)
Your function is actually producing and returning a string
Alternative Function
I'm going to critique ;) , you could shorten, and improve this function using the following.
var reverse_a_number = function (n){
return +(n += "").split("").reverse().join("");
}
What does this do?
n = n + '' has a special operator, +=. We can shorten this to on-line by using this inside parenthesis. The + will convert it into a Integer
A number doesn't have the split method. You have to convert it into a string, which does have split.
You can use typeof to find out the type of a variable. The following code snippet demonstrates the types of a number and a string, and shows the value of the split attribute for each one. Note that split is undefined for the number.
var n = 42;
document.write(typeof n, '<br />', n.split, '<br />', '<br />');
var s = ''+n;
document.write(typeof s, '<br />', s.split);
If you want to reverse an integer by treating it as an integer, without using string operations, you can do the following.
function reverseInteger(n) {
var result = 0;
while (n != 0) {
var digit = n%10;
result = 10*result + digit;
n = (n-digit)/10;
}
return result;
}
var n = 3141590123456;
document.write(n, '<br />');
document.write(reverseInteger(n));
Note that the last digit of n is n%10. If we subtract the last digit and divide n by ten, the effect is to shift n one digit to the right. We keep doing this and build up result in reverse by multiplying it by ten on each iteration and adding the digit that we just removed from n.

Extracting number from a string

What is the best way to get the number from a string.
The string will always start with n and end with any number i.e.:
n1
n2
n3
n10
n100
n1000
n99999
n9999999999999
and so on.
If you can guarantee the string will always look like that, then
num = parseInt(str.substring(1));
If it always starts with a single 'n', just keep it simple:
var number = parseInt(value.replace('n', ''));
Number.of = function (number) {
if (typeof number === "number")
return number;
var number = number + '',
regnum = /(-)?[0-9]+\.?[0-9]*/.exec(number);
return regnum ? (new Function('return ' + regnum[0]))() : 0;
};
Then just run..
Number.of('n12345'); // 12345
Mine is an incredibly careful approach to it, but what will pull a number out of anything.
Number.of('Hel5lo'); // 5
And always returns a number.
Number.of('There is no number here.'); // 0
That may or may not be helpful to you though.
You can use String.prototype.substr[docs] (or substring) and an unary + to convert the string to a number:
var number = +str.substr(1);
I's suggest:
$('dt').each(
function(){
var n = $(this).text().substring(1);
$('<dd />').text(n).insertAfter($(this));
});
JS Fiddle demo.
It doesn't matter, obviously, which elements you choose to use (I opted for dt and dd for the implied relationship between the input and the output). The important part is the substring() function; the value of 1 refers to the starting point of the resulting substring (from the second character, as JavaScript works with zero-based arrays).
Had a second number been passed, in the form substring(1,4) the resulting substring would have started from the second character and ended with the fifth, unless the string on which substring() is working is of a length shorter than the second argument, in which case it's treated as being equal to the length of the string.
Reference:
substring() at the Mozilla Developer Center.

why do I get 24 when adding 2 + 4 in javascript

I am trying this:
function add_things() {
var first = '2';
var second = '4';
alert(first + second);
}
But it gives me 24 instead of 6, what am I doing wrong?
You're concatenating two strings with the + operator. Try either:
function add_things() {
var first = 2;
var second = 4;
alert(first + second);
}
or
function add_things() {
var first = '2';
var second = '4';
alert(parseInt(first, 10) + parseInt(second, 10));
}
or
function add_things() {
var first = '2';
var second = '4';
alert(Number(first) + Number(second));
}
Note: the second is only really appropriate if you're getting strings from say a property or user input. If they're constants you're defining and you want to add them then define them as integers (as in the first example).
Also, as pointed out, octal is evil. parseInt('010') will actually come out as the number 8 (10 in octal is 8), hence specifying the radix of 10 is a good idea.
Try this:
function add_things() {
var first = 2;
var second = 4;
alert(first + second);
}
Note that I've removed the single quotes; first and second are now integers. In your original, they are strings (text).
That is one of the "Bad Parts" of JavaScript, as a loosely typed language, the addition and concatenation operator is overloaded.
JavaScript is loosely typed, but that doesn't mean that it has no data types just because a value of a variable, object properties, functions or parameters don't need to have a particular type of value assigned to it.
Basically there are three primitive data types:
boolean
number
string
null and undefined are two special cases, everything else are just variations of the object type.
JavaScript type-converts values of types into a type suitable for the context of their use (type coercion).
In your example were trying to add two objects of type string, so a concatenation occur.
You can "cast" or type convert the variables to number in many ways to avoid this problem:
var a = "2";
var b = "4";
// a and b are strings!
var sum = Number(a) + Number(b); // Number constructor.
sum = +a + +b; // Unary plus.
sum = parseInt(a, 10) + parseInt(b, 10); // parseInt.
sum = parseFloat(a) + parseFloat(b); // parseFloat.
This is I think a very common mistake, for example when reading user input from form elements, the value property of form controls is string, even if the character sequence that it contain represents a number (as in your example).
The "Bad Part" which I talk, is about the dual functionality of the + operator, overloaded to be used for both, numeric addition and string concatenation.
The operation that the + operator will do is determined completely by the context. Only if the both operands are numbers, the + operator perform addition, otherwise it will convert all of its operands to string and do concatenation.
The single quotes cause the values to be treated as characters instead of numbers. '2' + '4' = '24' in the same way that 'snarf' + 'blam' = 'snarfblam'.
You could also force the interpreter to perform arithmetic when dealing with numbers in string forms by multiplying the string by 1 (since multiplication can't be done on a string, it'll convert to a number if it can):
// fun with Javascript...
alert(first * 1 + second * 1);
But it's probably best to go with CMS's suggestion of using Number() to force the conversion, since someone will probably come along later and optimize the expression by removing the 'apparently unnecessary' multiply-by-one operations.

Categories

Resources