I've got this error message, that I'm not a fan of.
Bad line breaking before '?'.
I feel like
var s = (a === b)
? 'one'
: 'two';
looks better. Crockford says:
Semicolon insertion can mask copy/paste errors. If you always break lines after operators, then JSLint can do a better job of finding those errors.
Can someone give me an example or two, of the kind of copy/paste errors he's referring to?
Update:
var s = (a === b)
? 'one'
: 'two';
looks better than
var s;
if(a === b) {
s = 'one';
} else {
s = 'two';
}
(As requested, my comments re-posted as an answer:)
The "obvious" copy/paste error in the example you show would be to copy the first line:
var s = (a === b)
...which of course is valid code on its own but clearly doesn't do the same thing as the three lines together. One would hope that people would look at surrounding code before copying one line, but you never know.
The point that I think Mr Crockford is trying to make is that if you deliberately split a multi-line expression up in a way that the individual lines are not valid code on their own, then if you accidentally copy just one line of the expression it will likely cause a syntax error when you paste it somewhere else. Which is good because syntax errors are reported by the browser and/or JSLint/JSHint, and so easier to find than the more subtle bugs created if you copy/paste a line that is valid on its own. So if you "always break lines after operators" as Crockford suggest:
var s = (a === b) ?
'one' :
'two';
...then the only line of the ternary that is valid code on its own (the third) doesn't really look complete, and so would be easier to spot as a mistake if pasted on its own because it so obviously doesn't do anything on its own - and it's less likely to be copied by itself in the first place for the same reason.
(Having said that, I don't stress about the ternary operator in my own code, and I think the above looks ugly. I put a short ternary expression on one line, a longer one over two lines with the line break after the middle operand and the : lined up under the ?, or a really long one on three lines like yours.)
The most (in)famous example is as follows:
function one() {
return
{
val: 1
};
}
alert(one()); // undefined
vs
function one() {
return {
val: 1
};
}
alert(one()); // [objet Object]
The type of copy-paste errors he's referring to are the ones where you hand your code off to someone else, or yourself in 6 months, and that other person haphazardly copies your code, ending on the closing paren of the condition, assuming that the assignment is meant to be the value of the evaluated right-hand side.
This seems implausible, and in a sense, you would hope that it is...
But I know that auto-insertion has borked code for my company multiple times, now, and they still haven't forced adoption of explicit semicolons, still treat JS as if new lines were significant and still make cut/paste errors, through neglect plus lack of tools/version-management/build-systems.
Say you paste a function expression in immediately before,
var a = 1, b = 1; // a === b, expect 'one'
(function(){
console.log('called');
})
(a === b)
? 'one'
: 'two'
// called
// "two"
Related
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.
This is a question asking if such a technique exists..
I am looking for a way in general to do an inline statement that performs an action if the item object is defined else does nothing (so instead of (condition)?if:else; it is just (condition)?if;)
(item)?[item.member='foo']:0; //ReferenceError: item is not defined
var item={'member':'bar'};//item could be an object but it wasn't defined
I would have thought that there was a way beside 'try catch error'
for a hypothetical (somewhat impractical but best that I could think of) example
In the following snippet there might be lots of code surrounding the lines and many things going on. Is there a neat way to say only draw if the pen is defined as sometimes-but-not-always there is to be drawing done, sometimes no drawing - only the surrounding calculations instead. So the canvas is not always in use
//calculations and code
if(drawing===true){
var pen=document.getElementById('canvas');
pen=pen.getContext("2d");
//other canvas setup stuff
}
//calculations and code
pen.moveTo(0,0);
pen.lineTo(10,10);
the last two lines it would be great if there was some trick in JavaScript to do something like (pseudo code):
(pen) ? pen.lineTo(10,10);
This would throw unexpected ; error!
Is there a different kind of inline other than ternary and a way to return if the object is undefined?
There are two that I know of:
// Set a variable if not set
var x = x || 'hi';
// Do something if x is truthy
// Needs a scope, may not always be "this."
this.x && console.log(this.x);
So in your example, if pen is global, you can do window.pen && pen.lineTo(10, 10);
There's also the very simple one-line if:
if (pen) pen.lineTo(10, 10);
which technically isn't shorthand of any kind, it's just short. Compare the two line lengths (your pseudo-code versus this method):
(pen) ? pen.lineTo(10,10);
if (pen) pen.lineTo(10, 10);
Getting a bit more in-depth, I'd recommend against something like
if (pen) pen.moveTo(0, 0);
if (pen) pen.lineTo(10, 10);
because yes it's a couple of one-liners but you're doubling up logic, repeating yourself and you'll make people think "why did he do that?". In that situation, I'd just keep it simple:
if (pen) {
pen.moveTo(0, 0);
pen.lineTo(10, 10);
}
Yes, hoewever, you need to declare the variable somehow, e.g.:
// declare pen
var pen;
//calculations and code
if(drawing===true){
pen=document.getElementById('canvas');
pen=pen.getContext("2d");
//other canvas setup stuff
}
//calculations and code
pen && pen.moveTo(0,0);
pen && pen.lineTo(10,10);
//var pen; not declared
(!window.pen)&&console.log('no pen');
(window.pen)&&console.log('is pen');
this will print 'no pen' and will not throw error
var pen=document.getElementById('canvas');
pen=pen.getContext("2d");
(window.pen)&&pen.lineTo(10,10);
or if you don't use words reserved in jquery
$.pen=$('#canvas')[0];
pen=pen.getContext("2d");
($.pen)&&pen.lineTo(10,10);
Do a bunch of things in order:
($.pen)&&[
pen.lineTo(10,10),
pen.lineTo(20,20),
pen.lineTo(30,30)];
In my program there is a piece of code structured similar to this:
Number.prototype.print = function(){ console.log(this); };
var a = 1,
b = a + 2
(a - b).print()
However, when this gets executed, it throws an error saying "number is not a function". What is happening here and why is this error get thrown?
In JavaScript semicolons are automatically inserted in most cases. However, seems like the people who developed ES likes to make things more complicated by setting up weird rules for where to put semicolons.
In this case, they decided not to insert semicolon for you, therefore the code becomes this:
var a = 1, b = a + 2(a - b).print()
As you can see, 2 is interpreted as a function reference, and of course, 2 as a primitive is not a function and thus the error.
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.
I'm creating a text editor and I've just finished writing the highlighting algorithms to have each of the syntax appear in a different color, and render in the right position using the proper parse trees.
I was wondering if anyone could provide me with, or the location of a test or series of test cases to make sure nothing will break. The test case(s) should cover all of JavaScript syntax as it is used on the web including edge cases (i.e., including syntax like throw although it is rarely used), DOM creation and manipulation etc.
I have added the following static test case. It should cover all the syntax.
There are a few things to note: since the code is being parse recursively on a grammar level, only basic cases are required. For example, to the editor:
a[1]; and a[1][2][3][4][5]; would be the same syntax. Since the second line, is just recursively more subs then the the first line.
The test case I have created has been moved to an answer below.
Interesting question. I think my initial approach, barring any other interesting suggestions here, would be to grab a bunch of JavaScript from fairly major libraries. I'm thinking jQuery, Mootools, Prototype, etc.
Then, once you've done a few major libs, do some smaller ones. I'd checkout Github. Maybe look at Underscore, HeadJS, and maybe some others at https://github.com/languages/JavaScript.
I would also take a couple minified libraries, run them through JSBeautifier. Not sure if beautified JS may have slightly altered syntax from the original.
Lastly, I would consider running some of these libraries through JSLint, and then manually go through and modify the sources to explicitly hit some of the 'rules' that JSLint has laid out.
EDIT: And by "hit", I mean make sure you cover both scenarios offered by each rule, not just the 'clean' version.
One possible approach: there are various applications that will generate random pieces of code starting from a BNF grammar of a language (such as this one) and there are grammar files for javascript available.
That won't get you a static test case that you can script tests against with known expected results, necessarily, but might be a good way to test your parser against unexpected (but legal) strings and make sure it doesn't break.
This is so far the best test case I was able to come up with.
EDIT: Added regexp, and throw. This case is syntactically valid and should cover all cases of JS. Please message me directly if you find anything missing so that I can add it here.
a = 1;
b = { 'a' : a };
c = 'a';
d = this;
var patt1=/w3ghouls/i;
throw "Err3";
function e(a,b,c){
d += a + b + c++;
return d;
}
this.xy.z = function(a, b){
var x = null;
}
var f = function(a,b){
if(a == b || (b === a && a)){
var f = [a,b];
try{
f = f.slice(0);
}catch(e){
console.log(e * e + '');
}
}else if(a){
a = null;
a = undefined;
b = typeof a;
b = true;
b = false;
}else{
switch(c){
case 'c':
break;
default:
null;
break;
}
}
}
for(var i =0; i <= a.length; i++){
do{
continue;
null;
}while(a != b);
}
if(a == b)
(a) ? null : null;
/* This is a finished
test case */
A good way to start would be to run this through JSLint to see if your JavaScript is valid. It is the best checking tool I know of, but I'm not sure how well it will do to check if code broken. :(
Hope that helps.