I am well aware of similar questions, but I still can't solve mine basing on those.
So, my code looks like this:
for (var e, i = 0; e = formErrors[i]; i += 1)
JSHint returns said error in char 39, so with ; after formErrors[i]. What can I do?
JSHint is warning you of a potential bug. It is expected that the 2nd part of a for statement will be a Boolean expression. Normally, you'd use one of the comparison operators for this (==, ===, !=, > etc..). Since the expression is e = formErrors[i] it looks like it might be a mistake, possibly due to a missing equal sign. This is a common typo that causes a lot of bugs.
Apparently, in this case it is not a bug, but rather an intentional usage of the fact that any expression evaluates to something, and an assignment expression evaluates to the assigned value:
var x;
alert(x = 1);
So the for statement actually assigns a new value to e, but also evaluates that value as a condition, casting it to Boolean if required.
You could refactor your code such that it both assigns the value and uses a casting operation that would satisfy JSHint and make the code a bit more obvious to the reader:
for (var e, i = 0; !!(e = formErrors[i]); i += 1)
The 2nd ! (the one directly in front of (e...) causes a casting to Boolean, but also negates it, the 1st ! reverts this negation.
That's just a very weird way of writing a loop. JsHint expects a boolean expression ("conditional") there, and judges that your assignment is a mistake and you actually wanted a comparison (== instead of =).
What you should do is switch to the following common array iteration idiom:
for (var i = 0; i < formErrors.length; i += 1) {
var e = formErrors[i];
…
(Which works the same as your original code for non-sparse formErrors arrays that contain no falsy values.)
Or alternatively, if you want to write non-idiomatic code, dump jshint :-)
e = formErrors[i] is an assignment, don't you want a condition there? use a comma after i=0 in that case, else put a condition after the semicolon.
Typically, the middle element in a for loop is the condition that is used to decide whether to continue the loop or not. You have an assignment there, if you wanted a condition you should use e === formErrors[i] (or with a double =, but that is usually not recommended).
An assignment can technically work, because e can be, for example, some object (true) or null (false). But that is considered bad coding style, usually, and won't make for very readable code.
Related
Regarding
p = 0;
(p+1)++;
> ReferenceError: Invalid left-hand side expression in postfix operation
and
p = 0;
++(p+4);
> ReferenceError: Invalid left-hand side expression in prefix operation
I just got a bit of a surprise, as I expected postfix/prefix operators to be ok with working on the resolution of the expression (brackets have the highest operator precedence).
Could someone give me with a line or three to explain what is happening here?
Thanks
EDIT: Thanks for the quick responses, first answer marked as the answer. I feel I should also point people to the indepth answer from #thefourtheye below
++ increments the value of a variable, so it is larger than before. Eg:
var x = 3;
x++;
alert(x); // will show 4
For there to be any point for this, the expression to the left of ++ must be accessible and mutable, otherwise the increment would be possible. Eg:
3++
doesn't make any sense, as 3 is a constant and can't be incremented. We don't want this to be possible:
3++;
alert(3); // outputs 4???
This is why your expression doesn't work. Ie:
var p = 2;
(p + 1)++;
has the same problem as above. (p + 1) will evaluate to 3, and ++ can't change the value of the constant 3.
You are trying to increment (), the increment/decrement operator can be apply on variable, try the sample code
(p++) + 1
OR
(++p) + 1
Remember that when you write p++, that actually gets translated to p = p + 1. The operators ++ and -- are convenience notation for incrementing/decrementing a variable for future use. But how is (p+1)++ or ++(p+4) supposed to be translated? Those sort of imply that 1 or 4 are being incremented/decremented for future use, which doesn't make sense.
When you have an expression like this
(expr)++;
These are the operations JavaScript will do internally
Resolve the actual object referenced by expr.
This step is important, because you can even do something like this
var a = {b: 1};
++a.b;
a.b++;
console.log(a.b);
# 3
Now, JavaScript has to resolve the actual object to be incremented. In this case, it will be b in a.
Get the value at the reference and convert that value to a Number.
This step is also very important, because you may even have values like this
var a = {b: '1'};
console.log(++a.b);
# 2
JavaScript will try its best to get a number value, instead of failing immediately.
Increment the number.
Store the new vale in expr. This is step where your expression is failing.
In your case expr is p + 1, when it is resolved the value would be just a numeral, whose value can never be changed. (You can never change the value of 1 to something else). So, after the incrementing part, when the new value has to be stored back, JavaScript doesn't find a valid reference to store it. That is why it throws this error.
ReferenceError: Invalid left-hand side expression in postfix operation
This error message is actually thrown from internal PutValue method. The very first step goes like this
If Type(V) is not Reference, throw a ReferenceError exception.
Reference: ECMA Script 5.1 Standard Specification for Prefix Increment Operator
What is the meaning of && in this JavaScript code?
function doIt(a) {
var b = a.parents(),
c = 1;
return b.each(function() {
jQuery(this).hasClass("free-content") && (c = 0)
}), c
}
normally I would think this would be a logical operator AND, but I can't figure out what it does in this line.
The logical AND operator in this case is used in place of an IF-statement. It will set c to 0 if jQuery(this).hasClass("free-content") returns a truthy value.
It's equivalent to:
if (jQuery(this).hasClass("free-content")) {
c = 0;
}
You wondering what it means is actually the reason I dislike this type of coding and consider it a bad practice. It's hard to read and can create confusion, which in turn can create bugs.
It's also worth noting what logical AND returns, if you want to use the returned value:
(Logical AND) 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.
Here's an example showing, in my opinion, bad code since it's hard to follow:
var foo = bar && baz || qux;
The above code is equivalent to:
var foo;
if (bar && baz) {
foo = baz;
} else {
foo = qux;
}
Summary: Do not use logical operators as a nifty way to replace IF-statements or to save keystrokes. It will most likely come back and bite you or someone else in the ass.
I know there will be people arguing against me on this (usually the same people who doesn't want to use semicolon because ASI), but it's just a really bad idea to write code that only an expert would understand. There's no argument against it.
return b.each(function () {
jQuery(this).hasClass("free-content") && (c = 0)
}), c
b.each loops over all entries in b, and checks whether the current element has the class free-content set. Only if that yields true, the second part of the expression is evaluated – because they are concatenated via &&, and JavaScript stops evaluating such an expression when the first part is false, because then the whole expression can’t become true any more.
So if there is an element with that class, the second part is evaluated – and thereby c is set to the value 0 (because that’s the assignment operator = there, and not a comparison).
And after that each loop is finished, the value of c is returned to the outside – because each() and c are connected via the comma operator , here, which evaluates its operands from left to right and then “returns” the second one.
JavaScript allows a lot of “fancy” coding like this, but as Marcus already said in his answer, that is hard to read, and there is no actual advantage here over, say
b.each(function() {
if(jQuery(this).hasClass("free-content")) {
c = 0;
return false;
}
});
return c;
I added the return false here inside the each loop, because once we found an element with that class, we don’t need to search the rest of them any more – that’s something that the person who came up with the original code forgot to do in all their “fancy-ness” … their loop will continue to iterate over all of b’s elements, not matter if it finds the element it is looking for in the first round already.
Recently I saw a statement that works in javascript on the internet and I wonder what the meaning of a single equal sign (=) in javascript as I mostly use in if statements is.
It is a comparison function which include double equal sign (==)
if(i = 1) {
alert(i);
}
This works, I wondered what would happen when the if statement gets assigned to the value of 1 to the variable i and check the value of i which is the same as:
i = 1
if(i) {
alert(i)
}
But I soon realised that the assignation of a value variable needs to have the keyword var
so I changed the code to:
if(var i = 1) {
alert(i);
}
This time the code doesn't work. Why?
The first part of your analysis is of course correct.
Now, the interesting part might be why your last code if (var ...) { doesn't work.
It doesn't work because
1)
var something
is a statement, not an expression.
2) here's how ECMAScript defines the if statement :
IfStatement :
if ( Expression ) Statement else Statement
if ( Expression ) Statement
You must put an expression in the if clause, not a statement.
More on expressions vs statement in this article.
If you check the console, it says Unexpected token var. You're just not supposed to declare variables in the condition of an if statement.
If you ever do actually mean to make an assignment inside the condition, just declare the variable first, like this:
var i;
if(i = 1){
alert(i);
}
I see that you already know the difference between assignment and comparison, though, which is good :)
Single = is indeed an assignation, if you put it in the if condition it will not compare i against 1 but assign the variable i with the value 1 and then use that value as the condition itself, making i a truthy value. So yes, it is the same as you second example.
Also, in javascript it is better to use === instead of == if you are expecting the items to be the same type :
if (1 == '1') {
alert('this is true'); // where you might actually expect it to be false,
in this case it will work properly if you use triple equals (===).
if (1 === '1') {
alert('this is false'); // which is expected
}
Single = is an assignment operator and will always equate to true in an if statement (assuming it is a non negative value).
Double = ,as in ==, is a comparison and will equate to true only if the values on either side of the operator are equal.
Single "=" means "assign to the left var".
As a return value for the IF, you get the value assigned, and since it is 1, the "true" branch is executed.
However, if you put "var" into the IF, it won't return the assigned value, and I think it won't even work at all.
Mistaking "=" and "==" is a common typo.
Your assertion is correct, in that the code is essentially assigning the value 1 to i and then evaluating the expression's truthiness (1 coeerces to true, so the condition passes).
The last example fails because you can't declare variables inside condition expression.
When you don't explicitly invoke the var keyword, the value will be assigned to any existing variable called i that's available in your scope, or, if none exists, create a property i and assign it to the global object (window), which are all callable without invoking the global object (which is why calling, say location will refer back to window.location — unless you've defined var location in scope).
I stumbled across some javascript syntax that seemed like it should produce a parse error of some kind but doesn't:
if (true, true) {console.log('splendid')} else {console.log('horrid')} // splendid
if (true, false) {console.log('splendid')} else {console.log('horrid')} // horrid
It seems only the last expression affects the logic, though all expressions are executed:
if (console.log('super'), true) {console.log('splendid')} // super splendid
Anyone know why that is valid javascript syntax? Is there any practical use for it?
The comma operator chains multiple expressions together, and the result of the operation is the value of the last operand. The only real use for it is when you need multiple side effects to occur, such as assignment or function calls.
The comma operator evaluates each of its operands (from left to right)
and returns the value of the last operand.
https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Operators/Special_Operators/Comma_Operator
https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Expressions_and_Operators#comma_operator
commas in javascript are actually pretty arcane. The coolest use I have seen is this
while(doSomething(), checkIfSomethingHappened());
the most common would be the way var is used in modern js
var foo = 1,
bar = 2;
This is also the same as in most other programming languages where you might have multiple iterators in a loop.
int x,y;
for(x = 0, y = 0; x < 10 || y < 100; x++, y++) {
....
}
I permits to do operations and comparisons in the same context.
Example:
if(a = 2, a > 1) console.log('a is', a)
I came across a piece of code that is:
for(i=((90.0E1,0x5A)<=(0x158,140.70E1)?(.28,3.45E2,0):(95.30E1,26.40E1)<=1.400E2?(1,this):(108.,0x227));i<length;i++) {
// some other code here
}
Can someone help me by explaining the stuff in the for() brackets?
The result of the comma operator is always the value to the right hand side.
So each pair of the form (a,b) evaluates to b. Since in your code "a" never has a side effect, we can
simply omit it to get:
for(i=(0x5A <= 140.70E1 ? 0 : ...);i<length;i++) {
Where "..." stands for stuff that doesn't matter:
Since 0x5A <= 140.70E1 evaluates to true, the result of the ?: operator is the value to the right of the question mark, i.e. 0.
So the result is equivalent to
for (i=0; i<length; i++) {
which makes sense.
It is a standard three-expression for statement, where the first expression, the initializer, happens to be defined as
i = ((90.0E1,0x5A)<=(0x158,140.70E1)?(.28,3.45E2,0):(95.30E1,26.40E1)<=1.400E2?(1,this):(108.,0x227))
In this expression, the ternary ?: operator, and, to complicate things, does this in a nested fashion.
The syntax of the ?: operator is the following
condition ? value if true : value if false
Given this, the expression is composed of the following
condition: (90.0E1,0x5A)<=(0x158,140.70E1)
value if true: (.28,3.45E2,0)
value if false: (95.30E1,26.40E1)<=1.400E2?(1,this):(108.,0x227)
The value-if-false holds a nested expression using the ?: operator which can of course be deconstructed in the same way.
Simplifying the hex and E numbers, it becomes:
for(i=((900,90)<=(344,1407)?(.28,345,0):(953,264)<=140?(1,this):(108.,551));i<length;i++)
((900,90)<=(344,1407)?(.28,345,0):(953,264)<=140?(1,this):(108.,551)) == 0;
which makes the code equivalent to:
for(i=0;i<length;i++)
It's a very creative and confusing way to make a for loop, and a good joke.