`x = y, z` comma assignment in JavaScript [duplicate] - javascript

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript syntax: what comma means?
I came across the code while reading this article (do a Ctrl+F search for Andre Breton):
//function returning array of `umbrella` fibonacci numbers
function Colette(umbrella) {
var staircase = 0, galleons = 0, brigantines = 1, armada = [galleons, brigantines], bassoon;
Array.prototype.embrace = [].push;
while(2 + staircase++ < umbrella) {
bassoon = galleons + brigantines;
armada.embrace(brigantines = (galleons = brigantines, bassoon));
}
return armada;
}
What does the x = (y = x, z) construct mean? Or more specifically, what does the y = x, z mean? I'm calling it comma assignment because it looks like assignment and has a comma.
In Python, it meant tuple unpacking (or packing in this case). Is it the same case here?

This is the comma operator.
The comma operator evaluates both of its operands (from left to right)
and returns the value of the second operand.
The resultant value when a,b,c,...,n is evaluated will always be the
value of the rightmost expression, however all expressions in the
chain are still evaluated (from left to right).
So in your case, the assignations would still be evaluated, but the final value would be bassoon.
Result:
galleons = brigantines
brigantines = bassoon
armada.embrace(basson)
More information: Javascript "tuple" notation: what is its point?

var syntax allows multiple assignment, so when you see the following, you're declaring multiple variables using one var statement.
var a, b, c;
Note that this syntax is not the comma operator.
The , can be used as the comma operator. It simply evaluates a series of expressions. So when you see the following syntax, you are seeing a series of expressions being evaluated, and the return value of the last one being returned.
x = (y = x, z)
Within the parens, x is assigned to y, then z is evaluated and returned from the () and assigned to x.
I'd suggest that this syntax is unclear and offers little benefit.

The comma operand evaluates all of its operands and returns the last one. It makes no difference in this case if we had used
x = (y = x, z);
or
y = x;
x = z;
It's there to take away that line of code.

Related

Why is n += 1 not equivalent to n++ [duplicate]

I have a very simple arithmetic operator but am at my wits end why it doesn't return 2. The code below returns 1. I thought that x++ equates to x = x + 1;
CODE
var x = 1;
document.write(x++);
However if I run the code as follows, it returns 2 as expected
CODE
var x = 1;
document.write(++x);
What am I doing wrong?
PostIncrement(variable++) & PostDecrement(variable--)
When you use the ++ or -- operator after the variable, the variable's value is not incremented/decremented until after the expression is evaluated and the original value is returned. For example x++ translates to something similar to the following:
document.write(x);
x += 1;
PreIncrement(++variable) & PreDecrement(--variable)
When you use the ++ or -- operator prior to the variable, the variable's value is incremented/decremented before the expression is evaluated and the new value is returned. For example ++x translates to something similar to the following:
x += 1;
document.write(x);
The postincrement and preincrement operators are available in C, C++, C#, Java, javascript, php, and I am sure there are others languages. According to why-doesnt-ruby-support-i-or-i-increment-decrement-operators, Ruby does not have these operators.
I think of x++ and ++x (informally) as this:
x++:
function post_increment(x) {
return x; // Pretend this return statement doesn't exit the function
x = x + 1;
}
++x:
function pre_increment(x) {
x = x + 1;
return x;
}
The two operations do the same thing, but they return different values:
var x = 1;
var y = 1;
x++; // This returned 1
++y; // This returned 2
console.log(x == y); // true because both were incremented in the end
If you take a look at the javascript specification pages 70 and 71 you can see how it should be implemented:
Prefix:
Let expr be the result of evaluating UnaryExpression.
Throw a SyntaxError exception if the following conditions are all true:72 © Ecma International 2011
Type(expr) is Reference is true
IsStrictReference(expr) is true
Type(GetBase(expr)) is Environment Record
GetReferencedName(expr) is either "eval" or "arguments"
Let oldValue be ToNumber(GetValue(expr)).
Let newValue be the result of adding the value 1 to oldValue, using the same rules as for the + operator (see
11.6.3).
Call PutValue(expr, newValue).
Return newValue.
Or more simply:
Increment value
Return value
Postfix:
Let lhs be the result of evaluating LeftHandSideExpression.
Throw a SyntaxError exception if the following conditions are all true:
Type(lhs) is Reference is true
IsStrictReference(lhs) is true
Type(GetBase(lhs)) is Environment Record
GetReferencedName(lhs) is either "eval" or "arguments"
Let oldValue be ToNumber(GetValue(lhs)).
Let newValue be the result of adding the value 1 to oldValue, using the same rules as for the + operator (see
11.6.3).
Call PutValue(lhs, newValue).
Return oldValue.
Or more simply:
Assign value to temp
Increment value
Return temp

Unambiguous increment and adding results in error

When playing around with JavaScript syntax it struck me that the following code will throw an error in SpiderMonkey and V8 engines:
var a = 1, b = 1;
a++++b;
This to me is strange, since the following works perfectly fine:
var a = 1, b = 1;
a+++b; // = 2; (Add a and b, then increase a)
// now a == 2 and b == 1
a+++-b; // = 1; (add a and -b, then increase a)
// now a == 3 and b == 1
In addition, the following would be nonsensical code:
var a = 1, b = 1;
a++ ++b; // throws an error
My argument is now that if a+++b is equivalent to a++ + b, and not to a+ ++b, and a+++-b is equivalent to a++ + -b, then a++++b can only be interpreted as a++ + +b in order for it to be valid JavaScript code.
Instead, the engines insist that a++++b is interpreted as a++ ++b, by operator precedence.
This to me is in contrast with the logic that the engines implements using the / symbol, as explained here, to distinguish between division and regular expressions. An example
var e = 30, f = 3, g = 2;
e/f/g; // == 5
e
/f/g; // == 5
/f/g; // is equivalent to new RegExp("f","g")
Here the argument is that because /f/g does not make sense as division in the last line, it is interpreted as a regular expression.
Obviously the / symbol gets a special treatment, in order to distinguish between division and regular expressions. But then why do ++ and -- not get a special treatment as well? (That is, outside operator precedence)
A second question is why operator precedence is not called only when the code is has multiple valid interpretations.
In the code a++++b you have two distinct statements: a++ and ++b with nothing to combine them. The + operator in the context of a++ + +b is actually a type converter (meant for turning strings into numbers) and has a different order of precedence which follows the others in the list.

Javascript syntax: equal signs and commas

I really didn't know what to call this question, neither what I could google for. I'm trying to understand the source code for the D3.js library and I've encountered two functions that I simply can't understand, due to the syntax that is new to me.
The first one is the number interpolator:
function d3_interpolateNumber(a, b) {
b -= a = +a;
return function(t) { return a + b * t; };
}
What's going on on the second line here? We're subtracting the value of b from the value of a and then...uhm, you lost me. How does this syntax work?
The other thing that confuses me, that I've seen in other places as well, is where the right-hand assignment of a variable consists of several variables separated by commas. As in:
var i = d3.interpolators.length, f;
What does this mean? These snippets are taken from https://github.com/mbostock/d3/blob/master/src/interpolate/number.js and
https://github.com/mbostock/d3/blob/master/src/interpolate/interpolate.js
The first line you're asking about is just two assignments. It's equivalent to this:
a = +a;
b -= a;
The +a is using the unary plus operator to convert a string to a number. So we are converting a to a number and then subtracting that number from b (and reassigning the new value to b).
The second bit of syntax you're asking about is simply a list of variable declarations. For example:
var a, b, c; // Declares 3 variables, all initialised to undefined
That's equivalent to this:
var a;
var b;
var c;
In your example, one of the declarations in the list also includes an assignment. Any number of them can, so this is valid too:
var a, b = 1, c = true, d;
An assignment is also an expression, which returns the value that is assigned. So this:
b -= a = +a;
is the same as:
b -= (a = +a);
or:
a = +a;
b -= a;
If the right hand side would really be values separated by comma, i.e:
var i = (d3.interpolators.length, f);
then the comma operator returns the value of the last operand, so it would be the same as:
d3.interpolators.length;
var i = f;
However, without the parentheses the comma is a separator between declared variables, not the comma operator, so it's the same as:
var i = d3.interpolators.length;
var f;
The second line is
b -= (a = +a);
Which means:
set a to +a (conversion to a number). Return this value outside of the parentheses.
Whatever value was returned, subtract it from b.
or
a=+a //converts a to an int
b-=a // or b=b-a
Remember, assignments return their value. So, alert(a=1) will alert 1.
On the other hand,
var i = d3.interpolators.length, f;
splits to:
var i = d3.interpolators.length;
var f;
This is just basically a way of saying "var applie to the following comma separated list"

jQuery: why is an integer being added to a variable like a string?

So I'm trying to take the variable that increments in a for statement, and add an integer to it... but for some reason, it's adding the integer as though it were a string; other operations like subtraction or multiplication work as expected.
Why is this happening? Edit: I've added the whole function; the problem in question is where I try to add 2 to the variable x.
What confuses me is that I'm able to use x no problem, in an .eq() object for example...
$(function() {
$('textarea').bind('paste', function (e){
inputGroup = $(this).parent();
var ob = $(this);
if (e.type == 'paste'){
setTimeout(function(){
var data = ob.val();
var tabbed = data.replace(/\n/g, "\t");
var cells = tabbed.split("\t");
for(var x in cells) {
foo = x + 2;
alert(foo);
$(inputGroup).find('input').eq(x).val(cells[x]);
}
}, 1);
}
});
});
Why is this happening?
Because x is a string that just looks like a number. Cast to Number first and you'll get the result you expect:
"1" + 2 = "12"
Number("1") + 2 = 3
EDIT : Now that I see you are using split to turn a string into an array, your problem is definitely that you are concatenating strings. Cast to Number first, and your problem is solved.
Yes other arithmetic operations will work, since they will implicitly cast the operands to Numbers. Confusingly, "2" * 3 will in fact evaluate to the integer 6. Welcome to Javascript.
-tjw
Without more code, specifically the initialization of cells, I can't tell you the exact reason. But you can simply call parseInt() on x to turn it into an integer for addition
for(var x in cells) {
foo = parseInt(x, 10) + 2;
$(inputGroup).find('input').eq(foo).val(cells[x]);
}
Because + is a String concatenation but there is no equivalent String method for * or / so when using those it cast the value as a Number. Just cast x as an integer:
for(var x in cells) {
foo = parseInt(x, 10) + 2;
$(inputGroup).find('input').eq(foo).val(cells[x]);
}
The 10 in parseInt is saying to use a base 10 number system (as opposed to hex 16, e.g.).
As others have mentioned, x is a string. That's why.
There's a nice trick for casting strings as numbers in JavaScript that hasn't been mentioned though:
for(var x in cells) {
// Without the "var" here, you're setting a global
// variable during each loop iteration.
var foo = +x + 2;
$(inputGroup).find('input').eq(foo).val(cells[x]);
}

How does javascript logical assignment work?

In javascript, if we have some code such as
var a = "one";
var b = q || a;
alert (b);
The logical OR operator will assign a's value to b, and the alert will be "one."
Is this limited to assignments only or can we use it everywhere?
It seems an empty string is treated the same as undefined. Is this right?
How does this work with AND variables? What about combinations of them?
What is a good example of when to use these idioms, or when not to?
For your q || a to evaluate to a, q should be a 'falsy' value. What you did is called "Short circuit evaluation".
Answering your questions:
The logical operators (like and - &&, or - ||) can be used in other situations too. More generally in conditional statements like if. More here
Empty string is not treated as undefined. Both are falsy values. There are a few more falsy values. More here
AND, or && in JavaScript, is not a variable. It is an operator
The idiom you have used is quite common.
var x = val || 'default'; //is generally a replacement for
var x = val ? val : 'default' //or
if (val)
var x = val;
else
var x = 'default';
The way || works in Javascript is:
If the left operand evaluates as true, return the left operand
Otherwise, return the right operand
&& works similarly.
You can make use of this for in-line existence checks, for example:
var foo = (obj && obj.property)
will set foo to obj.property if obj is defined and "truthy".
I'm not quite sure I follow your question. You can use an expression anywhere you can use an expression, and a logical operator on two expressions results in an expression.
alert(q||a);
alert(true||false);
var x=5;
var y=0;
if (y!=0 && x/y>2) { /*do something*/ }
The last bit is useful. Like most languages, Javascript 'short-circuits' ANDs and ORs. If the first part of an AND is false, it doesn't evaluate the second bit - saving you a divide-by-0. If the first part of an OR is true, it doesn't evaluate the second.
But you can use boolean operators anywhere you can use an expression.
Javascript evaluates logic by truethness/falseness. Values such as (false, "", null, undefined, 0, -0) are evaluated as logic false.
Combine this with the lazy evaluation, 'OR' operations are now evaluated from left to right and stops once true is found. Since, in your example, the truthness is not literally a boolean, the value is returned.
In this case:
x = 0; y = 5; alert(y || x)/*returns 5*/; alert(x || y)/*also returns 5*/;
this can also be other objects.
functionThatReturnsTrue() || functionThatDoesSomething();
This behavior is shared with other scripting languages like Perl. The logical OR operator can be used as a syntactic shorthand for specifying default values due to the fact that the logical OR operator stops evaluating its operands when it encounters the first expression that evaluates to true: "evaluate the first operand and if the value is interpreted as not false, assign it. Otherwise repeat for the second operand."
I find I often use this behavior to specify default values for function parameters. E.g.
function myFunction(foo, bar) {
var fooValue = foo || "a";
// no need to test fooValue -- it's guaranteed to be defined at this point
}
IMHO - don't use for boolean type assignment. It can be confusing. As undefined !== false, ie false itself is a value.
E.g. If u want to copy a field value from an object if and only if that field is defined
var bar.value = false;
var foo = true;
var foo = bar.value || foo; // ==> should be false as bar.value is defined
For boolean type assignment, u should really use
var foo = (bar.value !== undefined) ? bar.value : foo;

Categories

Resources