@@ -1360,64 +1360,108 @@ <h1>JavaScript Garden</h1>
1360
1360
1361
1361
< article > < section > < header > < h2 id ="semicolon "> Automatic semicolon insertion < a href ="#intro "> #top</ a > </ h2 > </ header >
1362
1362
< p > Although JavaScript has C style syntax, it does < strong > not</ strong > enforce the use of
1363
- semicolons in the source code. Since the parser still needs semicolons in order
1364
- to be able to figure out what the code should do , it inserts them
1365
- < strong > automatically </ strong > . </ p >
1366
- < p > When the parser encounters an error due to newline that is not preceded by a
1367
- semicolon, it will insert a semicolon automatically and try again. When the
1368
- parser still hits an error, it will raise it, otherwise it will simply proceed. </ p >
1369
- < p > The automatic insertion of semicolon is considered to be one of < strong > biggest </ strong >
1370
- design flaws in the language. It makes the below code work, but with a
1371
- completely different result than intended. </ p >
1372
- < pre > < code > return
1373
- {
1374
- foo: 1
1375
- }
1363
+ semicolons in the source code, it is possible to omit them. </ p >
1364
+ < p > But JavaScript is not a semicolon-less language , it in fact needs the
1365
+ semicolons in order to understand the source code. Therefore the JavaScript
1366
+ parser < strong > automatically </ strong > inserts them whenever it encounters a parse
1367
+ error due to a missing semicolon. </ p >
1368
+ < pre > < code > var foo = function() {
1369
+ } // parse error, semicolon expected
1370
+ test()
1371
+ </ code > </ pre >
1372
+ < p > Insertion happens, and the parser tries again. </ p >
1373
+ < pre > < code > var foo = function() {
1374
+ }; // no error, parser continues
1375
+ test()
1376
1376
</ code > </ pre >
1377
- < p > After the JavaScript parser fixed it, this will < strong > not</ strong > return an object which
1378
- has a property called < code > foo</ code > , it will instead simply return < code > undefined</ code > .</ p >
1379
- </ section > < section > < header > < h3 > How the parser "fixes" missing semicolons</ h3 > </ header >
1380
- < pre > < code > return // Error, semicolon expected. Automatic insertion happens
1381
- { // Block syntax is handle just fine
1377
+ < p > The automatic insertion of semicolon is considered to be one of < strong > biggest</ strong >
1378
+ design flaws in the language as it < em > can</ em > change the behavior of code.</ p >
1379
+ </ section > < section > < header > < h3 > How it works</ h3 > </ header >
1380
+ < p > The code below has no semicolons in it, so it is up to the parser to decide where
1381
+ to insert them.</ p >
1382
+ < pre > < code > (function(window, undefined) {
1383
+ function test(options) {
1384
+ log('testing!')
1385
+
1386
+ (options.list || []).forEach(function(i) {
1387
+
1388
+ })
1389
+
1390
+ options.value.test(
1391
+ 'long string to pass here',
1392
+ 'and another long string to pass'
1393
+ )
1394
+
1395
+ return
1396
+ {
1397
+ foo: function() {}
1398
+ }
1399
+ }
1400
+ window.test = test
1382
1401
1383
- // foo is not interpreted as property name, but as a label
1384
- foo: 1 // JavaScript supports single expression evaluation
1385
- // So 1 evaluates to 1 and no error is being raised
1402
+ })(window)
1386
1403
1387
- } // Automatic semicolon insertion
1388
- </ code > </ pre >
1389
- < p > After the parser has done its "magic", the resulting code has completely
1390
- different behavior.</ p >
1391
- < pre > < code > return; // implicitly returns undefined
1404
+ (function(window) {
1405
+ window.someLibrary = {}
1392
1406
1393
- // dead code
1394
- {
1395
- foo: 1
1396
- };
1407
+ })(window)
1397
1408
</ code > </ pre >
1398
- </ section > < section > < header > < h3 > Missing semicolons and evaluation </ h3 > </ header >
1399
- < pre > < code > var foo = function() {
1400
- } // missing semicolon after assignment
1409
+ < p > Below is the result of the parser's "guessing" game. </ p >
1410
+ < pre > < code > ( function(window, undefined ) {
1411
+ function test(options) {
1401
1412
1402
- (function() {
1403
- // do something in it's own scope
1404
- })();
1405
- </ code > </ pre >
1406
- < p > Again, the above code will behave < strong > drastically different</ strong > .</ p >
1407
- < pre > < code > var foo = function(){
1413
+ // Not inserted, lines got merged
1414
+ log('testing!')(options.list || []).forEach(function(i) {
1408
1415
1409
- }( // The parser does NOT insert a semicolon here
1410
- // call the anonymous function and pass another function in
1411
- function() {
1416
+ }); // <- inserted
1417
+
1418
+ options.value.test(
1419
+ 'long string to pass here',
1420
+ 'and another long string to pass'
1421
+ ); // <- inserted
1422
+
1423
+ return; <- inserted, breaks the return statement
1424
+ {
1425
+ foo: function() {}
1426
+ }; // <- inserted
1412
1427
}
1413
- )() // now call the result of the previous call
1428
+ window.test = test; // <- inserted
1429
+
1430
+ // The lines got merged again
1431
+ })(window)(function(window) {
1432
+ window.someLibrary = {}; //<- inserted
1433
+
1434
+ })(window); //<- inserted
1435
+ </ code > </ pre >
1436
+ < p > The parser drastically changed the behavior of the code above, in certain cases
1437
+ it does the < strong > wrong</ strong > thing.</ p >
1438
+ </ section > < section > < header > < h3 > Leading parenthesis</ h3 > </ header >
1439
+ < p > In case of a leading parenthesis, the parse will < strong > not</ strong > insert a semicolon.</ p >
1440
+ < pre > < code > log('testing!')
1441
+ (options.list || []).forEach(function(i) {})
1442
+ </ code > </ pre >
1443
+ < p > This code gets transformed into one line.</ p >
1444
+ < pre > < code > log('testing!')(options.list || []).forEach(function(i) {})
1445
+ </ code > </ pre >
1446
+ < p > Chances are < strong > very</ strong > high that < code > log</ code > does < strong > not</ strong > return a function, therefore the
1447
+ above will yield < code > TypeError</ code > saying that < code > undefined is not a function</ code > .</ p >
1448
+ </ section > < section > < header > < h3 > Broken < code > return</ code > statements</ h3 > </ header >
1449
+ < p > The JavaScript parse also does not correctly handle return statements which are
1450
+ followed by a new line. </ p >
1451
+ < pre > < code > return;
1452
+ { // gets interpreted as a block
1453
+
1454
+ // a label and a single expression statement
1455
+ foo: function() {}
1456
+ };
1414
1457
</ code > </ pre >
1458
+ < p > Instead it produces the above, that is simply a silent error</ p >
1415
1459
</ section > < section > < header > < h3 > In conclusion</ h3 > </ header >
1416
- < p > Semicolons should < strong > never</ strong > be omitted , it is also recommended to keep braces
1417
- on the same line with their associated statements and never omit them for one
1418
- line < code > if</ code > / < code > else</ code > statements. This will not only improve the consistency of the
1419
- code, it will also prevent the JavaScript parser from applying too much "magic"
1420
- to the code .</ p > </ section > </ article >
1460
+ < p > It is highly recommended to < strong > never</ strong > omit semicolons , it is also advocated to
1461
+ keep braces on the same line with their corresponding statements and to never omit
1462
+ them for one single- line < code > if</ code > / < code > else</ code > statements. Both of these measures will
1463
+ not only improve the consistency of the code, they will also prevent the
1464
+ JavaScript parser from changing its behavior .</ p > </ section > </ article >
1421
1465
< footer >
1422
1466
< p >
1423
1467
Copyright © 2011.
0 commit comments