At wtfjs, I found that the following is legal javascript.
",,," == Array((null,'cool',false,NaN,4)); // true
The argument (null,'cool',false,NaN,4) looks like a tuple to me, but javascript does not have tuples!
Some quick tests in my javascript console yields the following.
var t = (null,'cool',false,NaN,4); // t = 4
(null,'cool',false,NaN,4) === 4; // true
(alert('hello'), 42); // shows the alert and returns 42
It appears to behave exactly like a semicolon ; separated list of statements, simply returning the value of the last statement.
Is there a reference somewhere that describes this syntax and its semantics? Why does it exist, i.e. when should it be used?
You are seeing the effect of 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).
As already explained this behaviour is caused by , operator. Due to this the expression (null,'cool',false,NaN,4) will always evaluate to 4. So we have
",,," == Array(4)
Array(4) - creates new array with allocated 4 elements. At the time of comparison with the string this array is converted to string like it would be with Array(4).toString(). For arrays toString acts like join(',') method called on this array. So for the empty array of 4 elements join will produce the string ",,,".
Try this alert((null,'cool',false,NaN,4)) and then you can see.
demo
The reason is because the comma operator evaluates all the statements and return the last one.
Think of this line: a = 1, b = 2, c = 3; it will run each expression so in essence it will set the variables to what you want and return the last value (in this case 3)
Related
I have a twofold question which involves something I would consider to be incorrect Javascript code.
How is the following statement interpreted in Javascript, and why?
(1,2,3,4)
Why is there a difference between these two invocations:
var a = (1,2,3,4);
a();
which leads to a being equal to 4 and Uncaught TypeError: a is not a function being thrown, and
(1,2,3,4)();
which leads to Uncaught TypeError: (((1 , 2) , 3) , 4) is not a function?
How is the following statement interpreted in Javascript, and why?
(1,2,3,4)
That's a comma operator expression (actually, a chain of them) wrapped in grouping parentheses. The comma operator is quite unusual: It evalutes both of its operands, then takes the value of the second one as its value, throwing away the value of the first one. You have a chain of them there, so the value of 1 is evaluated, then 2, then 3, then 4, and the result of the comma operator chain is the value 4; the result of the grouped parentheses expression is therefore 4.
Why is there a difference between these two invocations:
var a = (1,2,3,4);
a();
Because of the syntax of the language. In the first case, it's clearly not a function call, as there's no value prior to the first ( to call. The parsing rules for a complex language like JavaScript are just that: Complex. The parser is context-sensitive, and knows how to differentiate between grouping parentheses and function-call parentheses.
which leads to a being equal to 4 and Uncaught TypeError: a is not a function being thrown, and
(1,2,3,4)();
which leads to Uncaught TypeError: (((1 , 2) , 3) , 4) is not a function?
In both cases, the error message is quoting the expression that yielded the result it then tried to call as a function.
There is an operator in JS (among other languages) called the comma operator. It simply takes two operands, and returns the rightmost one.
a = 1, 2; // a now equals 2
It is, however, not the same comma as the function parameter separator. It is an operator.
The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.
So, the statement (1,2,3,4); returns 4, so var a = (1,2,3,4); means that a is equal to 4 which, is not a function, thus the error.
Likewise, (1,2,3,4) is just a grouping of comma operators and not a function, thus the second error.
hope you can help. I've got an empty array in my project which fill up as certain buttons are pressed (using push()). I want to know when a certain set of elements are in the array.
In the below code, it seems to work, the 3 elements are all in the array so it prints 'yes'. If I take out the last element ("TR"), it prints 'nope'. However, if I take out either of the first 2 elements, it prints 'yes'. It seems to be only focusing on the last element in the includes() function.
Is there any way to have the include() or something similar, check to see if all elements are in my array? Keep in mind that the array could have many more elements and they won't be sorted.
Thanks in advance.
var arr = ["TL", "TM", "TR"];
if (arr.includes("TL" && "TM" && "TR")){
console.log("yes");
} else {
console.log("nope");
}
The issue is in your if statement because includes() returns a boolean based on the string parameter. A better way of doing this would be to use something like:
if(arr.includes("TL") && arr.includes("TM") && arr.includes("TR")) {
console.log("yes");
}
If you have lots of elements in your array I would suggest something more along the lines of:
var flag = true;
for(i=0; i<arr.length; i++) {
if(!arr.includes(arr[i])) {
flag = false;
}
}
if(flag) {
console.log("yes");
}
Even though the above answers show methods to get your desired result, I'm surprised no one has addressed why your original attempt didn't work. This gets into some foundational rules that JavaScript follows: how functions are called, logical operator evaluation, and operator precedence.
Calling arr.includes()
First off, you have a function includes which takes a single string argument. You have given this argument an expression instead of a string, so it is going to evaluate the expression. If the evaluation produces a string, it will return that value. If it produces a different type, it will attempt to convert the result to a string. So to clear it up, you haven't given it 3 strings to look for, but one expression that will be evaluated and become the string you are looking for.
Logical Operator Evaluation
But what is the value of that string? In JavaScript, the logical operators work in a way that can shortcut and return one of the values being evaluated. In most cases, we'd be comparing boolean values, and get true or false from the evaluation, but we're working with strings here, not booleans. Strings in JavaScript can be evaluated as "truthy" or "falsy", the former being any string that has length and the latter being a string with no length (an empty string). With this in mind, the shortcut functionality of the logical AND && operator will look at the first value in the expression, and if that value is "falsy" it will return that value. If that value is "truthy" it will look at the other side of the expression and return its value.
MDN describes this logic pretty well. Given expr1 && expr2 here's the logic:
Returns expr1 if it can be converted to false; otherwise, returns expr2. Thus, when used with Boolean values, && returns true if both operands are true; otherwise, returns false.
Order Precendence
Finally, a note on order precedence. Logical AND && is of equal precendence to itself, so your expression will read from left-to-right. If, say, your expression was "TL" || "TM" && "TR" the "TM" && "TR" expression would be evaluated first since logical AND && has a higher precendence than logical OR ||.
Evaluating Your Expression
Knowing all of this, we can pick apart what your expression is doing:
"TL" && "TM" && "TR" is comprised of all logical AND operators, so we will read this from left-to-right, starting with "TL" && "TM". Since "TL" is a truthy string, the other side of the expression is returned which is "TM". The next expression is then "TM" && "TR", of which "TM" is a truthy value, so "TR" is returned. In the end, the includes function is checking if the value of "TR" exists in the array, and ultimately returns true.
Again, do mark one of the others as answers here. Looping through the values you want to search for in the array is what you're looking for, and writing your own loop or using reduce accomplishes that, but I wanted to explain why your initial attempt probably seemed odd and clear up just what was happening.
This can be done cleanly using the reduce method of arrays. Here's how to do it with your example:
var arr = ["TL", "TM", "TR"];
var fails = ["TL"] // This will return false
var succeeds = ["TL", "TM", "TR"] // This will return true
var includesAll = (array_to_check) => arr.reduce(
(accumulator, current) => accumulator && array_to_check.includes(current),
true
)
if (includesAll(succeeds)){
console.log("yes");
} else {
console.log("nope");
}
I have a twofold question which involves something I would consider to be incorrect Javascript code.
How is the following statement interpreted in Javascript, and why?
(1,2,3,4)
Why is there a difference between these two invocations:
var a = (1,2,3,4);
a();
which leads to a being equal to 4 and Uncaught TypeError: a is not a function being thrown, and
(1,2,3,4)();
which leads to Uncaught TypeError: (((1 , 2) , 3) , 4) is not a function?
How is the following statement interpreted in Javascript, and why?
(1,2,3,4)
That's a comma operator expression (actually, a chain of them) wrapped in grouping parentheses. The comma operator is quite unusual: It evalutes both of its operands, then takes the value of the second one as its value, throwing away the value of the first one. You have a chain of them there, so the value of 1 is evaluated, then 2, then 3, then 4, and the result of the comma operator chain is the value 4; the result of the grouped parentheses expression is therefore 4.
Why is there a difference between these two invocations:
var a = (1,2,3,4);
a();
Because of the syntax of the language. In the first case, it's clearly not a function call, as there's no value prior to the first ( to call. The parsing rules for a complex language like JavaScript are just that: Complex. The parser is context-sensitive, and knows how to differentiate between grouping parentheses and function-call parentheses.
which leads to a being equal to 4 and Uncaught TypeError: a is not a function being thrown, and
(1,2,3,4)();
which leads to Uncaught TypeError: (((1 , 2) , 3) , 4) is not a function?
In both cases, the error message is quoting the expression that yielded the result it then tried to call as a function.
There is an operator in JS (among other languages) called the comma operator. It simply takes two operands, and returns the rightmost one.
a = 1, 2; // a now equals 2
It is, however, not the same comma as the function parameter separator. It is an operator.
The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.
So, the statement (1,2,3,4); returns 4, so var a = (1,2,3,4); means that a is equal to 4 which, is not a function, thus the error.
Likewise, (1,2,3,4) is just a grouping of comma operators and not a function, thus the second error.
I had read in some articles that in some languages, like in JavaScript, assignment operators can be used in conditional statements. I want to know what is the logic behind that operation? As far as I know, only comparison operators are allowed in condition checking statements.
Any expression is allowed in a condition checking statement. If the value of the expression isn't boolean, then it will be converted to boolean to determine what the statement should do.
You can for example use a number in an if statement:
if (1) { ... }
Any non-zero number will be converted to true.
In Javascript an assignment is also an expression, i.e. it has a value. The value of the expression is the same value that was assigned to the variable.
So, you can use an assignment expression in a condition checking statement, and the value of the expression is converted to boolean if needed:
if (x = 1) { ... }
Using an assignment in an condition checking statement can be useful, if the value that you assign should be used to control what happens. If you for example have a function that returns different values for the first calls, then a null when there are no more values, you can use that in a loop:
while (line = getLine()) {
document.write(line);
}
You can of couse do that with the assignment separated from the logic, but then the code gets more complicated:
while (true) {
line = getLine();
if (line == null) break;
document.write(line);
}
In JavaScript (and many other languages), when a value is assigned to a variable, the value "returned" is the value that was assigned to a variable. As such, such a statement can be used in a condition with any assigned value being evaluated in the standard way.
For example:
var y = 0;
if(x = y){
alert("Y(and thus X) is Truthy");
}
else{
alert("Y(and thus X) is Falsy");
}
There are two factors that combine to give this effect:
in many languages, including JavaScript, an expression of the form left = right evaluates to the new left. For example, a = b = c = 0 sets all of a, b, and c to zero.
in many languages, including JavaScript, a wide variety of values can be used as conditional expressions. if(7) is equivalent to if(true); so if(a = 7) is equivalent to a = 7; if(true) rather than to the presumably-intended if(a == 7).
Assigning a value with = returns that value. You can use it to make an assignment while testing if the outcome is truthy or falsey (null, 0, "" undefined, NaN, false)
if (myVar = myArgument) ...
//same as:
// myVar=myArgument;
// if (myArgument) ...
This assigns myArgument to myVar while testing myArgument. Another more specific example:
If (myVar = 3+2) ...
// same as:
// myVar=3+2;
// if (5) ...
The benefit is more compact, terse code, sometimes at the expense of clarity.
This could be used to make a condition check and also use the value after it, without writing more lines.
if (value = someFunction()) {
...
}
This is valid syntax, though highly discouraged. In quite a few languages this is explicitely forbidden, but some languages also does not make this rule (e.g. C).
This question already has answers here:
What does the comma operator do in JavaScript?
(5 answers)
Closed 8 years ago.
I don't get why this.array[0] equals 1 if this.array[0] = [(2,1)]?
What does Javascript do with the 2 and how do i reach/use it? How does parenthesis work inside arrays?
I'd like to do different things with X if the boolean before it is true or false.
this.array[0] = [(true, X)] and this.array[0] = [(false, X)].
Parenthesis in that context act as a statement with the last item passed being the passed value.
In other words:
(2, 1) === 1
The 2 is evaluated, however, so:
(foo(), bar())
is effectively doing:
foo();
return bar();
What you want in this case is [2, 1]
If you use the comma operator inside parentheses, it evaluates both items and returns the second. This is rarely used, but there are two canonical reasons for using the comma operator:
Loop Logic
You can use the comma operator to have more complex login in a loop, like this:
for (var i = 0, j = 10; i < a && j > b; i++, j--) { }
Side Effect in Condition
You can use the comma operator to execute a statement before evaluating a condition, like this:
if (DoX(), CheckIfXHasBeenDoneSuccessfully()) { }
Other than that, the comma operator is basically naff. In your parentheses, (2,1), both 2 and 1 are evaluated and 2 is ignored and 1 is returned. You can use parentheses inside an array, but you will almost never want to put commas inside of the parentheses.
What I believe you want is something like this:
var bool = true; //or false, if you like
if(bool){ this.array[0] = X }
else { this.array[0] = Y }
its not the parens, its the incredibly arcane comma. What a comma will do is that it will evaluate each expression in turn, and return the result of the last one.
Your snippet is either a bug, or someone being an ass. Its the sort of thing that is only rarely useful, and probably shouldnt even be used in those times due to how confusing it is to people.
I think you want array[0] = [2,1].
In javascript, the expression
(2, 1)
evaluates to 1. The parentheses cause the expression 2, 1 to get evaluated before the brackets turn it into an array.
You actually want
this.array[0] = [false, X];