What does JavaScript interpret `+ +i` as? - javascript

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);

Related

What does +a + +b mean in JavaScript?

There was an answer to a nested array problem on stack overflow that involved a return statement +a + +b. (no period) What is this? What does it do? It seems to add, but I'm not sure how it does that. How does it differ from a + b? The code is below, and it works:
var array= [1, 2, [3, 4], [], [5]];
var sum = array.toString().split(",").reduce(function(a, b) { return +a + +b;
});
console.log(sum);
The + before the variable is the unary + operator. You are probably familiar with the unary -, e.g. -x.
Both +x and -x convert x to a number, but -x also changes its sign. This is not the primary purpose of the existance of the unary +, but it is a nice sideeffect.
Therefore, the difference between a + b and +a + +b would be visible from this example:
x = '9'; // '9'
x = +'9'; // 9
x = '9' + '9'; // '99'
x = +'9' + +'9'; // 18
JavaScript is dynamically typed, but has no built-in operators for casting a value to ensure it is the right type for an operation. Consequently, various tricks are used when it's important that a value is treated as a number, or a string, etc.
In this case, the operator being used is the "unary +" which is the natural counterpart of the "unary -" that would be used to write a negative number: just as "-x" means "0 - x", "+x" means "0 + x". On a number, this has no effect, but other values will be converted to a number.
This is important because the "binary +" operator does different things depending on the type of its operands: if a was a string, a + b would mean "append two strings together" rather than "sum two numbers".
Given an imaginary cast_to_number function, the equation could be more readably written as return cast_to_number(a) + cast_to_number(b).
Assuming a or b were of type String, adding a + operator in front of it will coerce it to a number.
This ensures that ’1’ + ‘1’ will be 2 (addition of numbers) and not 11 (concatenation of strings).
javascript has a unary operator + and -, both of them converts the operand to a number type, but the - operator negate the result.
for example:
> -'20'
-20
> +'500' + +'600'
1100
The + unary operator is used for explicit coercion in JavaScript.
Even though some developers look down upon it, saying var num = 3 + +c; is rather ugly especially to people not aware of the coercion at hand, potentially even "error-like" looking piece of code.
The most common practical use of the + unary operator is probably to get a number timestamp of the date
var timestamp = +new Date(); // this works!
Perhaps a good piece of memorablia is the - unary operator, which for some reason our human brain seems much happier to interpret. Basically, if we see var x = -c; we presume the compiler:
Attempts to do a value to number coercion of the variable c
If it can return a number, flip the sign and return the negative number (-)
The + unary operator does the same thing, only without the sign flipping.

Why does "a + + b" work, but "a++b" doesn't?

I was fiddling around with different things, like this
var a = 1, b = 2;
alert(a + - + - + - + - + - + - + - + b); //alerts -1
and I could remove the spaces, and it would still work.
a+-+-+-+-+-+-+-+b
Then I tried
a + + b
It ran and evaluated to 3, but when I removed the spaces, (a++b) it wouldn't run, and it had a warning which read "Confusing plusses."
I can understand that in cases like
a+++++b
which could be interpreted as any of the following
(a++) + (++b)
(a++) + +(+b)
a + +(+(++b))
a + +(+(+(+b)))
that it would be confusing.
But in the case of
a++b
the only valid way to interpret this, as far as I can tell, is
a + +b
Why doesn't a++b work?
The Javascript parser is greedy (it matches the longest valid operator each time), so it gets the ++ operator from a++b, making:
(a++) b
which is invalid. When you put in spaces a + + b, the parser interprets it like this:
(a) + (+b)
which is valid and works out to be three.
See this Wikipedia article on Maximal munch for more details.
It's reading a++, then it encounters a b and doesn't know what to do with it.
This is b/c of the difference in unary operators.
"a + + b" is the same as "a + (+b)"
"a++b" is the same as "(a++) _ b" <--- there is a missing operator where the _ is
Javascript's operator precendence rules for the ++ increment operator has no left-right associativitity. That means a++b can be interpreted as a++ b or a ++b depending on the particular implementation. Either way, it's a syntax error, as you've got 2 variables, one unary-operator, and nothing joining the two variables.
In practical terms:
a = 1
b = 2;
a++ b; -> 2 2
a ++b; -> 1 3
What does 1 3 mean as JS code?
Most programming language parsers tries to get longest chunk of text that make sense, so when Javascript sees:
[a][][][][]
"variable a" - it make sense, let's see next character:
[a][+][][]
"will be adding to varaible a" - it make sense, let's see next character:
[a][+][+][]
"will post-increment variable a" - it make sense, let's see next character,
[a][+][+][b]
This does not make sense. I have two expressions (a++) and (b) and no infix operator between them.
If you make it a+ +b it will not find the ++ operator and it will work as a + + b.
Longest Match rule comes into picture here. It says parser has to take longest token into consideration starting from left to right (I assume Javascript's grammar is Left to Right). So just apply this rule and you will get your answer.
Parser will start from left and will make a, +, + & b separate tokens in case of "a + + b" (due to white space in between them). In case of "a++b" it will apply longest match rule and will create a++ & b as token. a++ b as an expression does not make any semantic sense hence it will not be compiled.
The answer is that ++ is an operator as well as +, and that + + is two + operators, not a ++ operator.
Although it's not Javascript, C++ has similar fun with + and ++ operators. This was investigated in one of the Gurus of the Week from way back when.

Javascript (+) sign concatenates instead of giving sum of variables

Why when I use this: (assuming i = 1)
divID = "question-" + i+1;
I get question-11 and not question-2?
Use this instead:
var divID = "question-" + (i+1)
It's a fairly common problem and doesn't just happen in JavaScript. The idea is that + can represent both concatenation and addition.
Since the + operator will be handled left-to-right the decisions in your code look like this:
"question-" + i: since "question-" is a string, we'll do concatenation, resulting in "question-1"
"question-1" + 1: since "queston-1" is a string, we'll do concatenation, resulting in "question-11".
With "question-" + (i+1) it's different:
since the (i+1) is in parenthesis, its value must be calculated before the first + can be applied:
i is numeric, 1 is numeric, so we'll do addition, resulting in 2
"question-" + 2: since "question-" is a string, we'll do concatenation, resulting in "question-2".
You may also use this
divID = "question-" + (i*1+1);
to be sure that i is converted to integer.
Use only:
divID = "question-" + parseInt(i) + 1;
When "n" comes from html input field or is declared as string, you need to use explicit conversion.
var n = "1"; //type is string
var frstCol = 5;
lstCol = frstCol + parseInt(n);
If "n" is integer, don't need conversion.
n = 1; //type is int
var frstCol = 5, lstCol = frstCol + n;
Since you are concatenating numbers on to a string, the whole thing is treated as a string. When you want to add numbers together, you either need to do it separately and assign it to a var and use that var, like this:
i = i + 1;
divID = "question-" + i;
Or you need to specify the number addition like this:
divID = "question-" + Number(i+1);
EDIT
I should have added this long ago, but based on the comments, this works as well:
divID = "question-" + (i+1);
divID = "question-" + parseInt(i+1,10);
check it here, it's a JSFiddle
Another alternative could be using:
divID = "question-" + (i - -1);
Subtracting a negative is the same as adding, and a minus cannot be used for concatenation
Edit: Forgot that brackets are still necessary since code is read from left to right.
Add brackets
divID = "question-" + (i+1);
using braces surrounding the numbers will treat as addition instead of concat.
divID = "question-" + (i+1)
The reason you get that is the order of precendence of the operators, and the fact that + is used to both concatenate strings as well as perform numeric addition.
In your case, the concatenation of "question-" and i is happening first giving the string "question=1". Then another string concatenation with "1" giving "question-11".
You just simply need to give the interpreter a hint as to what order of prec endence you want.
divID = "question-" + (i+1);
Joachim Sauer's answer will work in scenarios like this. But there are some instances where adding parentheses won’t help.
For example: You are passing “sum of value of an input element and an integer” as an argument to a function.
arg1 = $("#elemId").val(); // value is treated as string
arg2 = 1;
someFuntion(arg1 + arg2); // and so the values are merged here
someFuntion((arg1 + arg2)); // and here
You can make it work by using Number()
arg1 = Number($("#elemId").val());
arg2 = 1;
someFuntion(arg1 + arg2);
or
arg1 = $("#elemId").val();
arg2 = 1;
someFuntion(Number(arg1) + arg2);
var divID = "question-" + (parseInt(i)+1);
Use this + operator behave as concat that's why it showing 11.
Care must be taken that i is an integer type of variable. In javaScript we don't specify the datatype during declaration of variables, but our initialisation can guarantee that our variable is of a specific datatype.
It is a good practice to initialize variables of declaration:
In case of integers, var num = 0;
In case of strings, var str = "";
Even if your i variable is integer, + operator can perform concatenation instead of addition.
In your problem's case, you have supposed that i = 1, in order to get 2 in addition with 1 try using (i-1+2). Use of ()-parenthesis will not be necessary.
- (minus operator) cannot be misunderstood and you will not get unexpected result/s.
One place the parentheses suggestion fails is if say both numbers are HTML input variables.
Say a and b are variables and one receives their values as follows (I am no HTML expert but my son ran into this and there was no parentheses solution i.e.
HTML inputs were intended numerical values for variables a and b, so say the inputs were 2 and 3.
Following gave string concatenation outputs: a+b displayed 23; +a+b displayed 23; (a)+(b) displayed 23;
From suggestions above we tried successfully : Number(a)+Number(b) displayed 5; parseInt(a) + parseInt(b) displayed 5.
Thanks for the help just an FYI - was very confusing and I his Dad got yelled at 'that is was Blogger.com's fault" - no it's a feature of HTML input default combined with the 'addition' operator, when they occur together, the default left-justified interpretation of all and any input variable is that of a string, and hence the addition operator acts naturally in its dual / parallel role now as a concatenation operator since as you folks explained above it is left-justification type of interpretation protocol in Java and Java script thereafter. Very interesting fact. You folks offered up the solution, I am adding the detail for others who run into this.
Simple as easy ... every input type if not defined in HTML is considered as string. Because of this the Plus "+" operator is concatenating.
Use parseInt(i) than the value of "i" will be casted to Integer.
Than the "+" operator will work like addition.
In your case do this :-
divID = "question-" + parseInt(i)+1;

What is the JSLint approved way to convert a number to a string?

I've always converted numbers to strings by adding an empty string to them:
var string = 1 + '';
However, JSLint complains of this method with Expected 'String' and instead saw ''''., and it does look a little ugly.
Is there a better way?
I believe that the JSLint approved way is to call .toString() on the number:
var stringified = 1..toString();
// Note the use of the double .. to ensure the the interpreter knows
// that we are calling the toString method on a number --
// not courting a syntax error.
// You could also theoretically call 1["toString"];
(Sorry, it possibly would've been better to say this as a comment above but I haven't yet earned the right to post comments, so...)
Remember that jslint is not just validating whether your JavaScript will actually run, it is trying to enforce coding style with the aim of helping you produce more readable and maintainable code.
So 1 + '' works, but isn't necessarily the most readable option for everybody while explicit casting options (see the other answers) should be readable for everybody. Of course if nobody else will ever see your code you need only worry about whether you will be able to understand it if you come back to it next month, or next year...
Don't forget that the following two statements don't produce the same result:
var s1 = 1 + 3 + ''; // gives '4'
var s2 = '' + 1 + 3; // gives '13'
I assume 1 + '' is just a simplification for discussion though, or why not just use '1' in the first place?
You can use the .toString() method like so:
var num = 1;
var str = num.toString();
There's also (at least in Chrome): String(1) without new.
var n = 1, s = String(n);
I am going to say "bug" or "mis-feature"
Cole Consider that
var x = "foobar" + 1;
is "approved" jslint. In any case, it is 100% valid Javascript.
Happy coding.
For comment:
This is why I prefer to use the string literal as the first operand as this shows intent -- knowing a language is fundamental to using a language.
The only place the duck-typing is an issues (in this case) is with an expression of the form a + b, where neither is a string literal. In this case a (or b) may evaluate to a string where it was expected to evaluate to a number (this would trigger the string concatenation vs. the expected numeric addition). If any of the operands are a string literal the intent is well-defined/described.
This particular "issue", however, is not present in the posted code; nor would it be eliminated with the use of toString over a string literal.
In my opinion, we should use String(number) instead of number + '' or number.toString(), because
number + '' will trigger the JSLint error
number.toString() will fail in case number is null or undefined, and you will have TypeError: number is undefined / null
Recently, JSLint was in beta. The new version no longer complains about this code:
function convert(x) {
'use strict';
// alert(typeof x);
x = x + "";
// alert(typeof x);
return x;
}
convert(3);

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