[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"sanity-1a-wtfuzyoJ9GYSw5M_Osewqg4hcGvQDF2neW848iTY":3,"sanity-CakzvmkOg_4iACynpgHD8Mu_3PU6hwufaDUVQSV8ZSA":1627},{"data":4,"sourceMap":-1},{"latestPodcast":5,"latestReleases":14,"post":39,"recent":1602},[6],{"_id":7,"publishedAt":8,"slug":9,"sponsored":12,"title":13},"4d0175f4-40a8-47eb-9bb3-a453b326aa7d","2026-07-03T07:40:00.000Z",{"_type":10,"current":11},"slug","the-good-the-bad-and-the-ai-apps",null,"The good, the bad, and the AI apps",[15,21,27,33],{"_id":16,"publishedAt":17,"slug":18,"title":20},"eb5b66eb-9410-4329-83bb-22bbff39402a","2026-04-28T13:00:00.000Z",{"_type":10,"current":19},"turn-scattered-knowledge-into-trusted-intelligence","Turning scattered knowledge into trusted intelligence: Stack Internal 2026.3",{"_id":22,"publishedAt":23,"slug":24,"title":26},"369c2401-b62e-4a37-8ff8-bf603023ecad","2026-03-02T15:03:00.988Z",{"_type":10,"current":25},"what-s-new-at-stack-overflow-march-2026","What’s new at Stack Overflow: March 2026",{"_id":28,"publishedAt":29,"slug":30,"title":32},"5e9053a4-07ea-447c-91ea-29e0b6228537","2026-02-02T15:00:00.000Z",{"_type":10,"current":31},"what-s-new-at-stack-overflow-february-2026","What’s new at Stack Overflow: February 2026",{"_id":34,"publishedAt":35,"slug":36,"title":38},"a1b538eb-a8a6-46d0-80a1-ac70ec9bb935","2026-01-05T10:00:00.000-05:00",{"_type":10,"current":37},"what-s-new-at-stack-overflow-january-2026","What’s new at Stack Overflow: January 2026",{"_createdAt":40,"_id":41,"_rev":42,"_type":43,"_updatedAt":44,"author":45,"body":61,"comments":1554,"dateUrl":1555,"excerpt":1556,"image":1557,"legacyBody":1560,"product":12,"publishedAt":1563,"slug":1564,"sponsored":12,"tags":1566,"title":1601,"visible":1554},"2023-05-25T09:39:12Z","wp-post-12612","MqLNOsFfWNrEK75cxDrGY5","blogPost","2023-11-08T20:51:30Z",[46],{"_createdAt":47,"_id":48,"_rev":49,"_type":50,"_updatedAt":51,"avatar":52,"employee":57,"name":58,"slug":59},"2023-05-23T16:27:18Z","wp-author-228","dgl3SCUzppW3U2LvCoP35A","blogAuthor","2023-06-20T15:05:08Z",{"_type":53,"asset":54},"image",{"_ref":55,"_type":56},"image-4035d87115e3b0301fe29f95cc8b23a9e6594d9d-1024x1024-jpg","reference","none","Ryland Goldstein",{"current":60},"rgoldstein",[62,94,113,122,149,166,183,186,201,209,212,215,218,221,229,236,243,251,267,270,278,281,289,292,295,298,301,317,331,347,350,358,366,370,378,386,408,416,419,422,441,444,447,455,476,479,482,503,506,509,546,568,645,652,708,715,765,787,806,809,812,820,823,826,842,850,853,869,884,887,905,913,916,924,927,935,938,946,960,968,971,979,993,1001,1004,1007,1015,1018,1026,1029,1032,1040,1043,1046,1054,1067,1078,1089,1097,1116,1119,1135,1138,1146,1157,1160,1168,1171,1179,1182,1197,1200,1208,1211,1232,1235,1238,1288,1296,1336,1339,1354,1362,1370,1384,1387,1399,1413,1430,1442,1456,1486,1497,1512,1520],{"_key":63,"_type":64,"children":65,"markDefs":89,"style":93},"2b64244278a8","block",[66,72,77,81,85],{"_key":67,"_type":68,"marks":69,"text":71},"2b64244278a80","span",[70],"em","In our 2019 Dev Survey, we asked what kind of content Stack Overflow users would like to see beyond questions and answers. The most ",{"_key":73,"_type":68,"marks":74,"text":76},"2b64244278a81",[70,75],"fdd4ade37782","popular response",{"_key":78,"_type":68,"marks":79,"text":80},"2b64244278a82",[70]," was “tech articles written by other developers.” So from now on we'll be regularly publishing articles from contributors. ",{"_key":82,"_type":68,"marks":83,"text":84},"2b64244278a83",[],"If ",{"_key":86,"_type":68,"marks":87,"text":88},"2b64244278a84",[70],"you have an idea and would like to submit a pitch, you can email pitches@stackoverflow.com.",[90],{"_key":75,"_type":91,"href":92,"reference":12},"link","https:\u002F\u002Finsights.stackoverflow.com\u002Fsurvey\u002F2019#community-_-opinions-on-new-content-types","normal",{"_key":95,"_type":64,"children":96,"markDefs":110,"style":93},"3a8f772cfa58",[97,101,106],{"_key":98,"_type":68,"marks":99,"text":100},"3a8f772cfa580",[],"\nHey there, I'm Ryland Goldstein, a product guy working on ",{"_key":102,"_type":68,"marks":103,"text":105},"3a8f772cfa581",[104],"3f918ec331ff","Reshuffle over at Binaris",{"_key":107,"_type":68,"marks":108,"text":109},"3a8f772cfa582",[],". This is my second piece for Stack Overflow. Let's dig in!\n\nI don't see enough people talking about practical ways to improve at JavaScript. Here are some of the top methods I use to write better JS.\n\n",[111],{"_key":104,"_type":91,"href":112,"reference":12},"https:\u002F\u002Fblog.binaris.com\u002Fa-shift-in-thinking\u002F",{"_key":114,"_type":64,"children":115,"markDefs":120,"style":121},"886626ec8c11",[116],{"_key":117,"_type":68,"marks":118,"text":119},"886626ec8c110",[],"Use TypeScript",[],"h2",{"_key":123,"_type":64,"children":124,"markDefs":146,"style":93},"b5a37b52f671",[125,129,134,138,142],{"_key":126,"_type":68,"marks":127,"text":128},"b5a37b52f6710",[],"The number one thing you can do to improve your JS is by not writing JS. For the uninitiated, ",{"_key":130,"_type":68,"marks":131,"text":133},"b5a37b52f6711",[132],"c9054ebb7ab3","TypeScript (TS)",{"_key":135,"_type":68,"marks":136,"text":137},"b5a37b52f6712",[]," is a \"compiled\" superset of JS (anything that runs in JS runs in TS). TS adds a comprehensive optional typing system on top of the vanilla JS experience. For a long time, TS support across the ecosystem was inconsistent enough for me to feel uncomfortable recommending it. Thankfully, those days are long behind us and most frameworks support TS out of the box. Now that we're all on the same page about what TS ",{"_key":139,"_type":68,"marks":140,"text":141},"b5a37b52f6713",[70],"is",{"_key":143,"_type":68,"marks":144,"text":145},"b5a37b52f6714",[],", let's talk about why you would want to use it.",[147],{"_key":132,"_type":91,"href":148,"reference":12},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMicrosoft_TypeScript",{"_key":150,"_type":64,"children":151,"markDefs":164,"style":165},"2dd489ecbe72",[152,156,161],{"_key":153,"_type":68,"marks":154,"text":155},"2dd489ecbe720",[],"\n",{"_key":157,"_type":68,"marks":158,"text":160},"2dd489ecbe721",[159],"strong","TypeScript enforces type safety",{"_key":162,"_type":68,"marks":163,"text":155},"2dd489ecbe722",[],[],"h3",{"_key":167,"_type":64,"children":168,"markDefs":182,"style":93},"8234cdcb5c43",[169,173,178],{"_key":170,"_type":68,"marks":171,"text":172},"8234cdcb5c430",[],"Type safety describes a process where a compiler verifies that all types are being used in a legal way throughout a piece of code. In other words, if you create a function ",{"_key":174,"_type":68,"marks":175,"text":177},"8234cdcb5c431",[176],"code","foo",{"_key":179,"_type":68,"marks":180,"text":181},"8234cdcb5c432",[]," that takes a number:",[],{"_key":184,"_type":176,"code":185,"markDefs":12},"3575f5caa050","function foo(someNum: number): number {\n  return someNum + 5;\n}",{"_key":187,"_type":64,"children":188,"markDefs":200,"style":93},"e2251af0e061",[189,193,196],{"_key":190,"_type":68,"marks":191,"text":192},"e2251af0e0610",[],"That ",{"_key":194,"_type":68,"marks":195,"text":177},"e2251af0e0611",[176],{"_key":197,"_type":68,"marks":198,"text":199},"e2251af0e0612",[]," function should only ever be called with a number:\n",[],{"_key":202,"_type":64,"children":203,"markDefs":208,"style":93},"3be20923fd01",[204],{"_key":205,"_type":68,"marks":206,"text":207},"3be20923fd010",[],"",[],{"_key":210,"_type":176,"code":211,"markDefs":12},"d2fa4a674766","good",{"_key":213,"_type":176,"code":214,"markDefs":12},"1a7a333b66b3","console.log(foo(2)); \u002F\u002F prints \"7\"",{"_key":216,"_type":176,"code":217,"markDefs":12},"4cf6de74d428","no good",{"_key":219,"_type":176,"code":220,"markDefs":12},"b1bb851be42f","console.log(foo(\"two\")); \u002F\u002F invalid TS code",{"_key":222,"_type":64,"children":223,"markDefs":228,"style":93},"202b3bb9315c",[224],{"_key":225,"_type":68,"marks":226,"text":227},"202b3bb9315c0",[],"Aside from the overhead of adding types to your code, there are zero downsides to type-safety enforcement. The benefit on the other hand, is too large to ignore. Type safety provides an extra level of protection against common errors\u002Fbugs, which is a blessing for a lawless language like JS.\n",[],{"_key":230,"_type":64,"children":231,"markDefs":235,"style":93},"d8e61758bf37",[232],{"_key":233,"_type":68,"marks":234,"text":207},"d8e61758bf370",[],[],{"_key":237,"_type":64,"children":238,"markDefs":242,"style":93},"f40d1365d308",[239],{"_key":240,"_type":68,"marks":241,"text":155},"f40d1365d3080",[],[],{"_key":244,"_type":64,"children":245,"markDefs":250,"style":165},"818f325723e8",[246],{"_key":247,"_type":68,"marks":248,"text":249},"818f325723e80",[159],"Typescript types make refactoring larger applications possible",[],{"_key":252,"_type":64,"children":253,"markDefs":266,"style":93},"49aee1f199d8",[254,258,262],{"_key":255,"_type":68,"marks":256,"text":257},"49aee1f199d80",[],"Refactoring a large JS application can be a true nightmare. Most of the pain of refactoring JS is due to the fact that it doesn't enforce function signatures. This means a JS function can never really be misused. For example, if I have a function ",{"_key":259,"_type":68,"marks":260,"text":261},"49aee1f199d81",[176],"myAPI",{"_key":263,"_type":68,"marks":264,"text":265},"49aee1f199d82",[]," that is used by 1000 different services:",[],{"_key":268,"_type":176,"code":269,"markDefs":12},"b64597bccae1","function myAPI(someNum, someString) {\n  if (someNum > 0) {\n    leakCredentials();\n  } else {\n    console.log(someString);\n  }\n}",{"_key":271,"_type":64,"children":272,"markDefs":277,"style":93},"bb3c9d2ecf62",[273],{"_key":274,"_type":68,"marks":275,"text":276},"bb3c9d2ecf620",[],"and I change the call signature a bit:",[],{"_key":279,"_type":176,"code":280,"markDefs":12},"09270c8d9e0f","function myAPI(someString, someNum) {\n  if (someNum > 0) {\n    leakCredentials();\n  } else {\n    console.log(someString);\n  }\n}",{"_key":282,"_type":64,"children":283,"markDefs":288,"style":93},"a435eaeebec8",[284],{"_key":285,"_type":68,"marks":286,"text":287},"a435eaeebec80",[],"I have to be 100% certain, that every place where this function is used (thousands of places), I correctly update the usage. If I even miss one my credentials could leak. Here's the same scenario with TS:",[],{"_key":290,"_type":176,"code":291,"markDefs":12},"c9e69791c2e7","before",{"_key":293,"_type":176,"code":294,"markDefs":12},"3def99204b81","function myAPITS(someNum: number, someString: string) { ... }",{"_key":296,"_type":176,"code":297,"markDefs":12},"f881ec288304","after",{"_key":299,"_type":176,"code":300,"markDefs":12},"105205749aaa","function myAPITS(someString: string, someNum: number) { ... }",{"_key":302,"_type":64,"children":303,"markDefs":316,"style":93},"fa0f3105c094",[304,308,312],{"_key":305,"_type":68,"marks":306,"text":307},"fa0f3105c0940",[],"As you can see, the ",{"_key":309,"_type":68,"marks":310,"text":311},"fa0f3105c0941",[176],"myAPITS",{"_key":313,"_type":68,"marks":314,"text":315},"fa0f3105c0942",[]," function went through the same change as the JavaScript counterpart. But instead of resulting in valid JavaScript, this code results in invalid TypeScript, as the thousands of places it's used are now providing the wrong types. And because of the type safety we discussed earlier, those thousand cases will block compilation and your credentials won't get leaked (that's always nice).\n",[],{"_key":318,"_type":64,"children":319,"markDefs":330,"style":165},"732d547924ff",[320,323,327],{"_key":321,"_type":68,"marks":322,"text":155},"732d547924ff0",[],{"_key":324,"_type":68,"marks":325,"text":326},"732d547924ff1",[159],"TypeScript makes team architecture communication easier",{"_key":328,"_type":68,"marks":329,"text":155},"732d547924ff2",[],[],{"_key":332,"_type":64,"children":333,"markDefs":346,"style":93},"b385fe4ef99b",[334,338,342],{"_key":335,"_type":68,"marks":336,"text":337},"b385fe4ef99b0",[],"When TS is setup correctly, it will be difficult to write code without first defining your interfaces and classes. This provides a way to share concise, communicative architecture proposals. Before TS, other solutions to this problem existed, but none solved it natively without making you do extra work. For example, if I want to propose a new ",{"_key":339,"_type":68,"marks":340,"text":341},"b385fe4ef99b1",[176],"Request",{"_key":343,"_type":68,"marks":344,"text":345},"b385fe4ef99b2",[]," type for my backend, I can send the following to a teammate using TS.",[],{"_key":348,"_type":176,"code":349,"markDefs":12},"3d644c4c4820","interface BasicRequest {\n  body: Buffer;\n  headers: { [header: string]: string | string[] | undefined; };\n  secret: Shhh;\n}",{"_key":351,"_type":64,"children":352,"markDefs":357,"style":93},"c5da713fd51c",[353],{"_key":354,"_type":68,"marks":355,"text":356},"c5da713fd51c0",[],"I already had to write the code, but now I can share my incremental progress and get feedback without investing more time. I don't know if TS is inherently less bug-prone than JS. I do strongly believe that forcing developers to define interfaces and APIs first results in better code.",[],{"_key":359,"_type":64,"children":360,"markDefs":365,"style":93},"930ecb1f4ca3",[361],{"_key":362,"_type":68,"marks":363,"text":364},"930ecb1f4ca30",[],"Overall, TS has evolved into a mature and more predictable alternative to vanilla JS. Developers definitely still need to be comfortable with vanilla JS, but most new projects I start these days are TS from the outset.\n\n",[],{"_key":367,"_type":53,"alt":12,"asset":368,"markDefs":12},"33b66f8f9806",{"_ref":369,"_type":56},"image-d80f323a09fcd16d8fdd319a586bcd3658827336-600x500-png",{"_key":371,"_type":64,"children":372,"markDefs":377,"style":121},"53abc8310b11",[373],{"_key":374,"_type":68,"marks":375,"text":376},"53abc8310b110",[],"\nUse Modern Features",[],{"_key":379,"_type":64,"children":380,"markDefs":385,"style":93},"7884d285be27",[381],{"_key":382,"_type":68,"marks":383,"text":384},"7884d285be270",[],"JavaScript is one of the most popular (if not the most) programming languages in the world. You might expect that a 20+ year old language used by hundreds of millions of people would be mostly figured out by now, but the opposite is actually true. In recent times, many changes and additions have been made to JS (yes I know, technically ECMAScript), fundamentally morphing the developer experience. As someone who only started writing JS in the last two years, I had the advantage of coming in without bias or expectations. This resulted in much more pragmatic choices about what features of the language to utilize and which to avoid.",[],{"_key":387,"_type":64,"children":388,"markDefs":407,"style":165},"460c3cfee5fc",[389,392,396,400,404],{"_key":390,"_type":68,"marks":391,"text":155},"460c3cfee5fc0",[],{"_key":393,"_type":68,"marks":394,"text":395},"460c3cfee5fc1",[159,176],"async",{"_key":397,"_type":68,"marks":398,"text":399},"460c3cfee5fc2",[159]," and ",{"_key":401,"_type":68,"marks":402,"text":403},"460c3cfee5fc3",[159,176],"await",{"_key":405,"_type":68,"marks":406,"text":155},"460c3cfee5fc4",[],[],{"_key":409,"_type":64,"children":410,"markDefs":415,"style":93},"34f0211fa12d",[411],{"_key":412,"_type":68,"marks":413,"text":414},"34f0211fa12d0",[],"For a long time, asynchronous, event-driven callbacks were a unavoidable part of JS development:",[],{"_key":417,"_type":176,"code":418,"markDefs":12},"65d00f31a9de","traditional callback",{"_key":420,"_type":176,"code":421,"markDefs":12},"c536306a455e","makeHttpRequest('google.com', function (err, result) {\n  if (err) {\n    console.log('Oh boy, an error');\n  } else {\n    console.log(result);\n  }\n});",{"_key":423,"_type":64,"children":424,"markDefs":438,"style":93},"a0d030d542bc",[425,429,434],{"_key":426,"_type":68,"marks":427,"text":428},"a0d030d542bc0",[],"I'm not going to spend time explaining why the above is problematic (",{"_key":430,"_type":68,"marks":431,"text":433},"a0d030d542bc1",[432],"9b859ef4c13c","but I have before",{"_key":435,"_type":68,"marks":436,"text":437},"a0d030d542bc2",[],"). To solve the issue with callbacks, a new concept—Promises—were added to JS. Promises allow you to write asynchronous logic while avoiding the nesting issues that previously plagued callback-based code.",[439],{"_key":432,"_type":91,"href":440,"reference":12},"http:\u002F\u002Fcdevn.com\u002Fparallel-computing-simplified-starring-gordon-ramsay",{"_key":442,"_type":176,"code":443,"markDefs":12},"c7505259b538","Promises",{"_key":445,"_type":176,"code":446,"markDefs":12},"3d86cd746194","makeHttpRequest('google.com').then(function (result) {\n  console.log(result);\n}).catch(function (err) {\n  console.log('Oh boy, an error');\n});",{"_key":448,"_type":64,"children":449,"markDefs":454,"style":93},"2ae3ef3d62a4",[450],{"_key":451,"_type":68,"marks":452,"text":453},"2ae3ef3d62a40",[],"The biggest advantage of Promises over callbacks is readability and chainability.",[],{"_key":456,"_type":64,"children":457,"markDefs":475,"style":93},"0ef73a857f11",[458,462,465,468,471],{"_key":459,"_type":68,"marks":460,"text":461},"0ef73a857f110",[],"While Promises are great, they still left something to be desired. For many, the Promise experience was still too reminiscent of callbacks. Specifically, developers were asking for an alternative to the Promise model. To remedy this, the ECMAScript committee decided to add a new method of utilizing promises, ",{"_key":463,"_type":68,"marks":464,"text":395},"0ef73a857f111",[176],{"_key":466,"_type":68,"marks":467,"text":399},"0ef73a857f112",[],{"_key":469,"_type":68,"marks":470,"text":403},"0ef73a857f113",[176],{"_key":472,"_type":68,"marks":473,"text":474},"0ef73a857f114",[],":",[],{"_key":477,"_type":176,"code":478,"markDefs":12},"f672cf4c41e7","\nasync and await\n",{"_key":480,"_type":176,"code":481,"markDefs":12},"4998c061ae83","try {\n  const result = await makeHttpRequest('google.com');\n  console.log(result);\n} catch (err) {\n  console.log('Oh boy, an error');\n}",{"_key":483,"_type":64,"children":484,"markDefs":502,"style":93},"43b50294d24a",[485,489,492,496,499],{"_key":486,"_type":68,"marks":487,"text":488},"43b50294d24a0",[],"The one caveat being, anything you ",{"_key":490,"_type":68,"marks":491,"text":403},"43b50294d24a1",[176],{"_key":493,"_type":68,"marks":494,"text":495},"43b50294d24a2",[]," must have been declared ",{"_key":497,"_type":68,"marks":498,"text":395},"43b50294d24a3",[176],{"_key":500,"_type":68,"marks":501,"text":474},"43b50294d24a4",[],[],{"_key":504,"_type":176,"code":505,"markDefs":12},"2927a108baec","required definition of makeHttpRequest in prev example",{"_key":507,"_type":176,"code":508,"markDefs":12},"d4c359cf3047","async function makeHttpRequest(url) {\n  \u002F\u002F ...\n}",{"_key":510,"_type":64,"children":511,"markDefs":545,"style":93},"6a118ed2a1a6",[512,516,519,523,526,530,534,538,541],{"_key":513,"_type":68,"marks":514,"text":515},"6a118ed2a1a60",[],"It's also possible to ",{"_key":517,"_type":68,"marks":518,"text":403},"6a118ed2a1a61",[176],{"_key":520,"_type":68,"marks":521,"text":522},"6a118ed2a1a62",[]," a Promise directly since an ",{"_key":524,"_type":68,"marks":525,"text":395},"6a118ed2a1a63",[176],{"_key":527,"_type":68,"marks":528,"text":529},"6a118ed2a1a64",[]," function is really just a fancy Promise wrapper. This also means the ",{"_key":531,"_type":68,"marks":532,"text":533},"6a118ed2a1a65",[176],"async\u002Fawait",{"_key":535,"_type":68,"marks":536,"text":537},"6a118ed2a1a66",[]," code and the Promise code are functionally equivalent. So feel free to use ",{"_key":539,"_type":68,"marks":540,"text":533},"6a118ed2a1a67",[176],{"_key":542,"_type":68,"marks":543,"text":544},"6a118ed2a1a68",[]," without feeling guilty.\n",[],{"_key":547,"_type":64,"children":548,"markDefs":567,"style":165},"647fb193ca74",[549,552,556,559,563],{"_key":550,"_type":68,"marks":551,"text":155},"647fb193ca740",[],{"_key":553,"_type":68,"marks":554,"text":555},"647fb193ca741",[159,176],"let",{"_key":557,"_type":68,"marks":558,"text":399},"647fb193ca742",[159],{"_key":560,"_type":68,"marks":561,"text":562},"647fb193ca743",[159,176],"const",{"_key":564,"_type":68,"marks":565,"text":566},"647fb193ca744",[],"\n\n",[],{"_key":569,"_type":64,"children":570,"markDefs":644,"style":93},"3999f78a79f9",[571,575,579,583,586,590,593,597,600,604,607,610,613,617,620,624,627,631,634,637,640],{"_key":572,"_type":68,"marks":573,"text":574},"3999f78a79f90",[],"For most of JS's existence, there was only one variable scope qualifier: ",{"_key":576,"_type":68,"marks":577,"text":578},"3999f78a79f91",[176],"var",{"_key":580,"_type":68,"marks":581,"text":582},"3999f78a79f92",[],". ",{"_key":584,"_type":68,"marks":585,"text":578},"3999f78a79f93",[176],{"_key":587,"_type":68,"marks":588,"text":589},"3999f78a79f94",[]," has some pretty unique\u002Finteresting rules in regards to how it handles scope. The scoping behavior of ",{"_key":591,"_type":68,"marks":592,"text":578},"3999f78a79f95",[176],{"_key":594,"_type":68,"marks":595,"text":596},"3999f78a79f96",[]," is inconsistent and confusing and has resulted in unexpected behavior and therefore bugs throughout the lifetime of JS. But as of ES6, there is an alternative to ",{"_key":598,"_type":68,"marks":599,"text":578},"3999f78a79f97",[176],{"_key":601,"_type":68,"marks":602,"text":603},"3999f78a79f98",[],": ",{"_key":605,"_type":68,"marks":606,"text":562},"3999f78a79f99",[176],{"_key":608,"_type":68,"marks":609,"text":399},"3999f78a79f910",[],{"_key":611,"_type":68,"marks":612,"text":555},"3999f78a79f911",[176],{"_key":614,"_type":68,"marks":615,"text":616},"3999f78a79f912",[],". There is practically zero need to use ",{"_key":618,"_type":68,"marks":619,"text":578},"3999f78a79f913",[176],{"_key":621,"_type":68,"marks":622,"text":623},"3999f78a79f914",[]," anymore, so don't. Any logic that uses ",{"_key":625,"_type":68,"marks":626,"text":578},"3999f78a79f915",[176],{"_key":628,"_type":68,"marks":629,"text":630},"3999f78a79f916",[]," can always be converted to equivalent ",{"_key":632,"_type":68,"marks":633,"text":562},"3999f78a79f917",[176],{"_key":635,"_type":68,"marks":636,"text":399},"3999f78a79f918",[],{"_key":638,"_type":68,"marks":639,"text":555},"3999f78a79f919",[176],{"_key":641,"_type":68,"marks":642,"text":643},"3999f78a79f920",[]," based code.",[],{"_key":646,"_type":64,"children":647,"markDefs":651,"style":93},"665f99d26bba",[648],{"_key":649,"_type":68,"marks":650,"text":207},"665f99d26bba0",[],[],{"_key":653,"_type":64,"children":654,"markDefs":707,"style":93},"19cf563affd2",[655,659,662,666,669,673,676,679,682,686,689,693,696,700,703],{"_key":656,"_type":68,"marks":657,"text":658},"19cf563affd20",[],"As for when to use ",{"_key":660,"_type":68,"marks":661,"text":562},"19cf563affd21",[176],{"_key":663,"_type":68,"marks":664,"text":665},"19cf563affd22",[]," vs ",{"_key":667,"_type":68,"marks":668,"text":555},"19cf563affd23",[176],{"_key":670,"_type":68,"marks":671,"text":672},"19cf563affd24",[],", I always start by declaring everything ",{"_key":674,"_type":68,"marks":675,"text":562},"19cf563affd25",[176],{"_key":677,"_type":68,"marks":678,"text":582},"19cf563affd26",[],{"_key":680,"_type":68,"marks":681,"text":562},"19cf563affd27",[176],{"_key":683,"_type":68,"marks":684,"text":685},"19cf563affd28",[]," is far more restrictive and \"immutablish,\" which usually results in better code. There aren't a ton of \"real scenarios\" where using ",{"_key":687,"_type":68,"marks":688,"text":555},"19cf563affd29",[176],{"_key":690,"_type":68,"marks":691,"text":692},"19cf563affd210",[]," is necessary, I would say 1\u002F20 variables I declare with ",{"_key":694,"_type":68,"marks":695,"text":555},"19cf563affd211",[176],{"_key":697,"_type":68,"marks":698,"text":699},"19cf563affd212",[],". The rest are all ",{"_key":701,"_type":68,"marks":702,"text":562},"19cf563affd213",[176],{"_key":704,"_type":68,"marks":705,"text":706},"19cf563affd214",[],".",[],{"_key":709,"_type":64,"children":710,"markDefs":714,"style":93},"601a3158536b",[711],{"_key":712,"_type":68,"marks":713,"text":207},"601a3158536b0",[],[],{"_key":716,"_type":64,"children":717,"markDefs":764,"style":93},"2825f09130d2",[718,722,725,729,732,736,739,743,746,750,753,757,760],{"_key":719,"_type":68,"marks":720,"text":721},"2825f09130d20",[],"I said ",{"_key":723,"_type":68,"marks":724,"text":562},"2825f09130d21",[176],{"_key":726,"_type":68,"marks":727,"text":728},"2825f09130d22",[]," is \"immutablish\" because it does not work in the same way as ",{"_key":730,"_type":68,"marks":731,"text":562},"2825f09130d23",[176],{"_key":733,"_type":68,"marks":734,"text":735},"2825f09130d24",[]," in C\u002FC++. What ",{"_key":737,"_type":68,"marks":738,"text":562},"2825f09130d25",[176],{"_key":740,"_type":68,"marks":741,"text":742},"2825f09130d26",[]," means to the JavaScript runtime is that the reference to that ",{"_key":744,"_type":68,"marks":745,"text":562},"2825f09130d27",[176],{"_key":747,"_type":68,"marks":748,"text":749},"2825f09130d28",[]," variable will never change. This does not mean the contents stored at that reference will never change. For primitive types (number, boolean, etc.), ",{"_key":751,"_type":68,"marks":752,"text":562},"2825f09130d29",[176],{"_key":754,"_type":68,"marks":755,"text":756},"2825f09130d210",[]," does translate to immutability (because it's a single memory address). But for all objects (classes, arrays, dicts), ",{"_key":758,"_type":68,"marks":759,"text":562},"2825f09130d211",[176],{"_key":761,"_type":68,"marks":762,"text":763},"2825f09130d212",[]," does not guarantee immutability.\n",[],{"_key":766,"_type":64,"children":767,"markDefs":786,"style":165},"14a91c8fe531",[768,771,775,779,783],{"_key":769,"_type":68,"marks":770,"text":566},"14a91c8fe5310",[],{"_key":772,"_type":68,"marks":773,"text":774},"14a91c8fe5311",[159],"Arrow ",{"_key":776,"_type":68,"marks":777,"text":778},"14a91c8fe5312",[159,176],"=>",{"_key":780,"_type":68,"marks":781,"text":782},"14a91c8fe5313",[159]," Functions",{"_key":784,"_type":68,"marks":785,"text":566},"14a91c8fe5314",[],[],{"_key":788,"_type":64,"children":789,"markDefs":803,"style":93},"e17b5dab1323",[790,794,799],{"_key":791,"_type":68,"marks":792,"text":793},"e17b5dab13230",[],"Arrow functions are a concise method of declaring ",{"_key":795,"_type":68,"marks":796,"text":798},"e17b5dab13231",[797],"8c78d2ca6d90","anonymous functions",{"_key":800,"_type":68,"marks":801,"text":802},"e17b5dab13232",[]," in JS. Anonymous functions describe functions that aren't explicitly named. Usually, anonymous functions are passed as a callback or event hook.",[804],{"_key":797,"_type":91,"href":805,"reference":12},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FFunctions\u002FArrow_functions",{"_key":807,"_type":176,"code":808,"markDefs":12},"6745a6b4fb84","\nvanilla anonymous function\n",{"_key":810,"_type":176,"code":811,"markDefs":12},"a187ac5a2c78","someMethod(1, function () { \u002F\u002F has no name\n  console.log('called');\n});",{"_key":813,"_type":64,"children":814,"markDefs":819,"style":93},"6d79852586ef",[815],{"_key":816,"_type":68,"marks":817,"text":818},"6d79852586ef0",[],"For the most part, there isn't anything \"wrong\" with this style. Vanilla anonymous functions behave \"interestingly\" in regards to scope, which can\u002Fhas resulted in many unexpected bugs. We don't have to worry about that anymore thanks to arrow functions. Here is the same code implemented with an arrow function:\n",[],{"_key":821,"_type":176,"code":822,"markDefs":12},"92d19245c770","anonymous arrow function",{"_key":824,"_type":176,"code":825,"markDefs":12},"136a1829f068","someMethod(1, () => { \u002F\u002F has no name\n  console.log('called');\n});",{"_key":827,"_type":64,"children":828,"markDefs":841,"style":93},"04065586f14b",[829,833,837],{"_key":830,"_type":68,"marks":831,"text":832},"04065586f14b0",[],"Aside from being far more concise, arrow functions have much more practical scoping behavior. Arrow functions inherit ",{"_key":834,"_type":68,"marks":835,"text":836},"04065586f14b1",[176],"this",{"_key":838,"_type":68,"marks":839,"text":840},"04065586f14b2",[]," from the scope they were defined in.\n",[],{"_key":843,"_type":64,"children":844,"markDefs":849,"style":93},"1ef1864ef66b",[845],{"_key":846,"_type":68,"marks":847,"text":848},"1ef1864ef66b0",[],"In some cases, arrow functions can be even more concise:",[],{"_key":851,"_type":176,"code":852,"markDefs":12},"ad3bddf3a909","const added = [0, 1, 2, 3, 4].map((item) => item + 1);\nconsole.log(added) \u002F\u002F prints \"[1, 2, 3, 4, 5]\"",{"_key":854,"_type":64,"children":855,"markDefs":868,"style":93},"e56b2ae5e115",[856,860,864],{"_key":857,"_type":68,"marks":858,"text":859},"e56b2ae5e1150",[],"Arrow functions that reside on a single line include a implicit ",{"_key":861,"_type":68,"marks":862,"text":863},"e56b2ae5e1151",[176],"return",{"_key":865,"_type":68,"marks":866,"text":867},"e56b2ae5e1152",[]," statement. There is no need for brackets or semi-colons with single line arrow functions.\n",[],{"_key":870,"_type":64,"children":871,"markDefs":883,"style":93},"7480789d00cd",[872,876,879],{"_key":873,"_type":68,"marks":874,"text":875},"7480789d00cd0",[],"I want to make it clear. This isn't a ",{"_key":877,"_type":68,"marks":878,"text":578},"7480789d00cd1",[176],{"_key":880,"_type":68,"marks":881,"text":882},"7480789d00cd2",[]," situation; there are still valid use cases for vanilla anonymous functions (specifically class methods). That being said, I've found that if you always default to an arrow function, you end up doing a lot less debugging as opposed to defaulting to vanilla anonymous functions.\n",[],{"_key":885,"_type":176,"code":886,"markDefs":12},"9d67c0a8d9f6","As usual, the Mozilla docs are the best resource",{"_key":888,"_type":64,"children":889,"markDefs":904,"style":165},"d4a761f14a9a",[890,893,897,901],{"_key":891,"_type":68,"marks":892,"text":566},"d4a761f14a9a0",[],{"_key":894,"_type":68,"marks":895,"text":896},"d4a761f14a9a1",[159],"Spread Operator ",{"_key":898,"_type":68,"marks":899,"text":900},"d4a761f14a9a2",[159,176],"...",{"_key":902,"_type":68,"marks":903,"text":566},"d4a761f14a9a3",[],[],{"_key":906,"_type":64,"children":907,"markDefs":912,"style":93},"91fc1a77fff9",[908],{"_key":909,"_type":68,"marks":910,"text":911},"91fc1a77fff90",[],"Extracting key\u002Fvalue pairs of one object and adding them as children of another object is a very common scenario. Historically, there have been a few ways to accomplish this, but all of those methods are pretty clunky:",[],{"_key":914,"_type":176,"code":915,"markDefs":12},"edbe3bb252d0","const obj1 = { dog: 'woof' };\nconst obj2 = { cat: 'meow' };\nconst merged = Object.assign({}, obj1, obj2);\nconsole.log(merged) \u002F\u002F prints { dog: 'woof', cat: 'meow' }",{"_key":917,"_type":64,"children":918,"markDefs":923,"style":93},"f8349b499cb8",[919],{"_key":920,"_type":68,"marks":921,"text":922},"f8349b499cb80",[],"This pattern is incredibly common, so the above approach quickly becomes tedious. Thanks to the spread operator, there's never a need to use it again:",[],{"_key":925,"_type":176,"code":926,"markDefs":12},"7de1619ca227","const obj1 = { dog: 'woof' };\nconst obj2 = { cat: 'meow' };\nconsole.log({ ...obj1, ...obj2 }); \u002F\u002F prints { dog: 'woof', cat: 'meow' }",{"_key":928,"_type":64,"children":929,"markDefs":934,"style":93},"df631f94c5a3",[930],{"_key":931,"_type":68,"marks":932,"text":933},"df631f94c5a30",[],"The great part is, this also works seamlessly with arrays:",[],{"_key":936,"_type":176,"code":937,"markDefs":12},"23d9d6e578d2","const arr1 = [1, 2];\nconst arr2 = [3, 4];\nconsole.log([ ...arr1, ...arr2 ]); \u002F\u002F prints [1, 2, 3, 4]",{"_key":939,"_type":64,"children":940,"markDefs":945,"style":93},"f9b5627ed6ac",[941],{"_key":942,"_type":68,"marks":943,"text":944},"f9b5627ed6ac0",[],"It's probably not the most important recent JS feature, but it's one of my favorites.\n",[],{"_key":947,"_type":64,"children":948,"markDefs":959,"style":165},"41fc03377527",[949,952,956],{"_key":950,"_type":68,"marks":951,"text":566},"41fc033775270",[],{"_key":953,"_type":68,"marks":954,"text":955},"41fc033775271",[159],"Template Literals (Template Strings)",{"_key":957,"_type":68,"marks":958,"text":155},"41fc033775272",[],[],{"_key":961,"_type":64,"children":962,"markDefs":967,"style":93},"5fb14cb67329",[963],{"_key":964,"_type":68,"marks":965,"text":966},"5fb14cb673290",[],"Strings are one of the most common programming constructs. This is why it's so embarrassing that natively declaring strings is still poorly supported in many languages. For a long time, JS was in the \"crappy string\" family. But the addition of template literals put JS in a category of its own. Template literals natively and conveniently solve the two biggest problems with writing strings: adding dynamic content and writing strings that bridge multiple lines:",[],{"_key":969,"_type":176,"code":970,"markDefs":12},"4ff102ca2007","const name = 'Ryland';\nconst helloString =\n`Hello\n ${name}`;",{"_key":972,"_type":64,"children":973,"markDefs":978,"style":93},"82912ab00ec9",[974],{"_key":975,"_type":68,"marks":976,"text":977},"82912ab00ec90",[],"I think the code speaks for itself. What an amazing implementation.",[],{"_key":980,"_type":64,"children":981,"markDefs":992,"style":165},"418e1a4d34d7",[982,985,989],{"_key":983,"_type":68,"marks":984,"text":566},"418e1a4d34d70",[],{"_key":986,"_type":68,"marks":987,"text":988},"418e1a4d34d71",[159],"Object Destructuring",{"_key":990,"_type":68,"marks":991,"text":566},"418e1a4d34d72",[],[],{"_key":994,"_type":64,"children":995,"markDefs":1000,"style":93},"57a37c1f1742",[996],{"_key":997,"_type":68,"marks":998,"text":999},"57a37c1f17420",[],"Object destructuring is a way to extract values from a data collection (object, array, etc.), without having to iterate over the data or access its keys explicitly:\n",[],{"_key":1002,"_type":176,"code":1003,"markDefs":12},"48c16606ccb9","old way",{"_key":1005,"_type":176,"code":1006,"markDefs":12},"29fb304b27c4","function animalParty(dogSound, catSound) {}\n\nconst myDict = {\n  dog: 'woof',\n  cat: 'meow',\n};\n\nanimalParty(myDict.dog, myDict.cat);",{"_key":1008,"_type":64,"children":1009,"markDefs":1014,"style":93},"9b6bdb181542",[1010],{"_key":1011,"_type":68,"marks":1012,"text":1013},"9b6bdb1815420",[70],"destructuring",[],{"_key":1016,"_type":176,"code":1017,"markDefs":12},"4890b2c9ed84","function animalParty(dogSound, catSound) {}\n\nconst myDict = {\n  dog: 'woof',\n  cat: 'meow',\n};\n\nconst { dog, cat } = myDict;\nanimalParty(dog, cat);",{"_key":1019,"_type":64,"children":1020,"markDefs":1025,"style":93},"3d578ff319a6",[1021],{"_key":1022,"_type":68,"marks":1023,"text":1024},"3d578ff319a60",[],"But wait, there's more. You can also define destructuring in the signature of a function:\n",[],{"_key":1027,"_type":176,"code":1028,"markDefs":12},"b7d085c0170d","destructuring 2",{"_key":1030,"_type":176,"code":1031,"markDefs":12},"cde7d301091e","function animalParty({ dog, cat }) {}\n\nconst myDict = {\n  dog: 'woof',\n  cat: 'meow',\n};\n\nanimalParty(myDict);",{"_key":1033,"_type":64,"children":1034,"markDefs":1039,"style":93},"f112c5f1ee97",[1035],{"_key":1036,"_type":68,"marks":1037,"text":1038},"f112c5f1ee970",[],"It also works with arrays:",[],{"_key":1041,"_type":176,"code":1042,"markDefs":12},"1e073cb6fcdb","destructuring 3",{"_key":1044,"_type":176,"code":1045,"markDefs":12},"587f4959fba3","[a, b] = [10, 20];\n\nconsole.log(a); \u002F\u002F prints 10",{"_key":1047,"_type":64,"children":1048,"markDefs":1053,"style":93},"d06f592fdc43",[1049],{"_key":1050,"_type":68,"marks":1051,"text":1052},"d06f592fdc430",[],"There are a ton of other modern features you should be utilizing. Here are a handful of others that stand out to me:\n\n",[],{"_key":1055,"_type":64,"children":1056,"level":1062,"listItem":1063,"markDefs":1064,"style":93},"ff83762767ef",[1057],{"_key":1058,"_type":68,"marks":1059,"text":1061},"ff83762767ef0",[1060],"ca5b88524fac","Rest Parameter",1,"bullet",[1065],{"_key":1060,"_type":91,"href":1066,"reference":12},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FFunctions\u002Frest_parameters",{"_key":1068,"_type":64,"children":1069,"level":1062,"listItem":1063,"markDefs":1075,"style":93},"5f5af89cc8b5",[1070],{"_key":1071,"_type":68,"marks":1072,"text":1074},"5f5af89cc8b50",[1073],"79e140e6c7c6","Import Over Require",[1076],{"_key":1073,"_type":91,"href":1077,"reference":12},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fimport",{"_key":1079,"_type":64,"children":1080,"level":1062,"listItem":1063,"markDefs":1086,"style":93},"2dafa7908c5b",[1081],{"_key":1082,"_type":68,"marks":1083,"text":1085},"2dafa7908c5b0",[1084],"f02dc85855ff","Array Element Find",[1087],{"_key":1084,"_type":91,"href":1088,"reference":12},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FArray\u002Ffind",{"_key":1090,"_type":64,"children":1091,"markDefs":1096,"style":121},"319ab7529a58",[1092],{"_key":1093,"_type":68,"marks":1094,"text":1095},"319ab7529a580",[],"Always Assume Your System is Distributed",[],{"_key":1098,"_type":64,"children":1099,"markDefs":1113,"style":93},"bc34ca8aca64",[1100,1104,1109],{"_key":1101,"_type":68,"marks":1102,"text":1103},"bc34ca8aca640",[],"When writing parallelized applications your goal is to optimize the amount of work you're doing at one time. If you have four available cores and your code can only utilize a single core, 75% of your potential is being wasted. This means blocking, synchronous operations are the ultimate enemy of parallel computing. But considering that JS is a single threaded language, things don't run on multiple cores. So what's the point?\n\nJS is single threaded, but not single-file (as in lines at school). Even though it isn't parallel, it's still concurrent. Sending an HTTP request may take seconds or even minutes, so if JS stopped executing code until a response came back from the request, the language would be unusable.\n\nJavaScript solves this with an ",{"_key":1105,"_type":68,"marks":1106,"text":1108},"bc34ca8aca641",[1107],"0fca20bf8ece","event loop",{"_key":1110,"_type":68,"marks":1111,"text":1112},"bc34ca8aca642",[],". The event loop loops through registered events and executes them based on internal scheduling\u002Fprioritization logic. This is what enables sending thousands of simultaneous HTTP requests or reading multiple files from disk at the same time. Here's the catch: JavaScript can only utilize this capability if you utilize the correct features. The most simple example is the for-loop:",[1114],{"_key":1107,"_type":91,"href":1115,"reference":12},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FEventLoop",{"_key":1117,"_type":176,"code":1118,"markDefs":12},"2113b78eac2e","let sum = 0;\nconst myArray = [1, 2, 3, 4, 5, ... 99, 100];\nfor (let i = 0; i \u003C myArray.length; i += 1) {\n  sum += myArray[i];\n}",{"_key":1120,"_type":64,"children":1121,"markDefs":1134,"style":93},"a0e14351b93b",[1122,1126,1130],{"_key":1123,"_type":68,"marks":1124,"text":1125},"a0e14351b93b0",[],"A vanilla for-loop is one of the least parallel constructs that exists in programming. At my last job, I led a team that spent months attempting to convert traditional ",{"_key":1127,"_type":68,"marks":1128,"text":1129},"a0e14351b93b1",[176],"R",{"_key":1131,"_type":68,"marks":1132,"text":1133},"a0e14351b93b2",[]," lang for-loops into automagically parallel code. It's basically an impossible problem, only solvable by waiting for deep learning to improve. The difficulty of parallelizing a for-loop stems from a few problematic patterns. Sequential for-loops are very rare, but they alone make it impossible to guarantee a for-loops decomposability:",[],{"_key":1136,"_type":176,"code":1137,"markDefs":12},"5ea9307b9249","let runningTotal = 0;\nfor (let i = 0; i \u003C myArray.length; i += 1) {\n  if (i === 50 && runningTotal > 50) {\n    runningTotal = 0;\n  }\n  runningTotal += Math.random() + runningTotal;\n}",{"_key":1139,"_type":64,"children":1140,"markDefs":1145,"style":93},"edbfa9ad396a",[1141],{"_key":1142,"_type":68,"marks":1143,"text":1144},"edbfa9ad396a0",[],"This code only produces the intended result if it is executed in order, iteration by iteration. If you tried to execute multiple iterations at once, the processor might incorrectly branch based on inaccurate values, which invalidates the result. We would be having a different conversation if this was C code, as the usage is different and there are quite a few tricks the compiler can do with loops. In JavaScript, traditional for-loops should only be used if absolutely necessary. Otherwise, utilize the following constructs:",[],{"_key":1147,"_type":64,"children":1148,"markDefs":1156,"style":93},"a10e6cb6e0b0",[1149,1152],{"_key":1150,"_type":68,"marks":1151,"text":566},"a10e6cb6e0b00",[],{"_key":1153,"_type":68,"marks":1154,"text":1155},"a10e6cb6e0b01",[70],"map",[],{"_key":1158,"_type":176,"code":1159,"markDefs":12},"2c3bf30cc2ff","\u002F\u002F in decreasing relevancy :0\nconst urls = ['google.com', 'yahoo.com', 'aol.com', 'netscape.com'];\nconst resultingPromises = urls.map((url) => makHttpRequest(url));\nconst results = await Promise.all(resultingPromises);",{"_key":1161,"_type":64,"children":1162,"markDefs":1167,"style":93},"a68a615e2d04",[1163],{"_key":1164,"_type":68,"marks":1165,"text":1166},"a68a615e2d040",[70],"map with index",[],{"_key":1169,"_type":176,"code":1170,"markDefs":12},"65d9462fff61","\u002F\u002F in decreasing relevancy :0\nconst urls = ['google.com', 'yahoo.com', 'aol.com', 'netscape.com'];\nconst resultingPromises = urls.map((url, index) => makHttpRequest(url, index));\nconst results = await Promise.all(resultingPromises);",{"_key":1172,"_type":64,"children":1173,"markDefs":1178,"style":93},"b6bdd3cf102e",[1174],{"_key":1175,"_type":68,"marks":1176,"text":1177},"b6bdd3cf102e0",[70],"for-each",[],{"_key":1180,"_type":176,"code":1181,"markDefs":12},"5b796590ca62","const urls = ['google.com', 'yahoo.com', 'aol.com', 'netscape.com'];\n\u002F\u002F note this is non blocking\nurls.forEach(async (url) => {\n  try {\n    await makHttpRequest(url);\n  } catch (err) {\n    console.log(`${err} bad practice`);\n  }\n});",{"_key":1183,"_type":64,"children":1184,"markDefs":1196,"style":93},"499345d681a6",[1185,1189,1192],{"_key":1186,"_type":68,"marks":1187,"text":1188},"499345d681a60",[],"I'll explain why these are an improvement over traditional for-loops. Instead of executing each iteration in order (sequentially), constructs such as ",{"_key":1190,"_type":68,"marks":1191,"text":1155},"499345d681a61",[176],{"_key":1193,"_type":68,"marks":1194,"text":1195},"499345d681a62",[]," take all of the elements and submit them as individual events to the user-defined map function. For the most part, individual iterations have no inherent connection or dependence to each other, allowing them to run concurrently. This isn't to say that you couldn't accomplish the same thing with for-loops. In fact, it would look something like this:",[],{"_key":1198,"_type":176,"code":1199,"markDefs":12},"66111b871345","const items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\nasync function testCall() {\n  \u002F\u002F do async stuff here\n}\n\nfor (let i = 0; i \u003C 10; i += 1) {\n  testCall();\n}",{"_key":1201,"_type":64,"children":1202,"markDefs":1207,"style":93},"0203550912a6",[1203],{"_key":1204,"_type":68,"marks":1205,"text":1206},"0203550912a60",[],"As you can see, the for-loop doesn't prevent me from doing it the right way, but it sure doesn't make it any easier either. Compare to the map version:",[],{"_key":1209,"_type":176,"code":1210,"markDefs":12},"4c1f0d8f1a02","const items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\nitems.map(async (item) => {\n \u002F\u002F do async stuff here\n});",{"_key":1212,"_type":64,"children":1213,"markDefs":1231,"style":93},"28294d6932cb",[1214,1217,1220,1224,1227],{"_key":1215,"_type":68,"marks":1216,"text":307},"28294d6932cb0",[],{"_key":1218,"_type":68,"marks":1219,"text":1155},"28294d6932cb1",[176],{"_key":1221,"_type":68,"marks":1222,"text":1223},"28294d6932cb2",[]," just works. The advantage of the map becomes even more clear if you want to block until all of the individual async operations are done. With the for-loop code, you would need to manage an array yourself. Here's the ",{"_key":1225,"_type":68,"marks":1226,"text":1155},"28294d6932cb3",[176],{"_key":1228,"_type":68,"marks":1229,"text":1230},"28294d6932cb4",[]," version:",[],{"_key":1233,"_type":176,"code":1234,"markDefs":12},"b277029d3141","const items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n const allResults = await Promise.all(items.map(async (item) => {\n  \u002F\u002F do async stuff here\n }));",{"_key":1236,"_type":176,"code":1237,"markDefs":12},"f60ef20e362a","\nit's really that easy\n",{"_key":1239,"_type":64,"children":1240,"markDefs":1287,"style":93},"de300d54efba",[1241,1245,1248,1252,1256,1260,1264,1267,1270,1273,1277,1281,1284],{"_key":1242,"_type":68,"marks":1243,"text":1244},"de300d54efba0",[],"There are many cases where a for-loop would be just as performant (or maybe more) in comparison to a ",{"_key":1246,"_type":68,"marks":1247,"text":1155},"de300d54efba1",[176],{"_key":1249,"_type":68,"marks":1250,"text":1251},"de300d54efba2",[]," or ",{"_key":1253,"_type":68,"marks":1254,"text":1255},"de300d54efba3",[176],"forEach",{"_key":1257,"_type":68,"marks":1258,"text":1259},"de300d54efba4",[],". I would still argue that losing a few cycles now is worth the advantage of using a well defined API. That way, any future improvements to that data access patterns implementation will benefit your code. The for-loop is too generic to have meaningful optimizations for that same pattern.\n\n",{"_key":1261,"_type":68,"marks":1262,"text":1263},"de300d54efba5",[70],"There are a other valid async options outside of ",{"_key":1265,"_type":68,"marks":1266,"text":1155},"de300d54efba6",[70,176],{"_key":1268,"_type":68,"marks":1269,"text":399},"de300d54efba7",[70],{"_key":1271,"_type":68,"marks":1272,"text":1255},"de300d54efba8",[70,176],{"_key":1274,"_type":68,"marks":1275,"text":1276},"de300d54efba9",[70],", such as ",{"_key":1278,"_type":68,"marks":1279,"text":1280},"de300d54efba10",[70,176],"for-await-of",{"_key":1282,"_type":68,"marks":1283,"text":706},"de300d54efba11",[70],{"_key":1285,"_type":68,"marks":1286,"text":566},"de300d54efba12",[],[],{"_key":1289,"_type":64,"children":1290,"markDefs":1295,"style":121},"e96a090a4bbc",[1291],{"_key":1292,"_type":68,"marks":1293,"text":1294},"e96a090a4bbc0",[],"Lint Your Code and Enforce a Style",[],{"_key":1297,"_type":64,"children":1298,"markDefs":1329,"style":93},"3ec6f752da04",[1299,1303,1308,1311,1316,1320,1325],{"_key":1300,"_type":68,"marks":1301,"text":1302},"3ec6f752da040",[],"Code without a consistent style (look and feel) is incredibly difficult to read and understand. Therefore, a critical aspect of writing high-end code in any language is having a consistent and sensible style. Due to the breadth of the JS ecosystem, there are a LOT of options for linters and style specifics. What I can't stress enough is that it's far more important that you are using a linter and enforcing a style (any of them) than it is which linter\u002Fstyle you specifically choose. At the end of the day, no one is going to write code exactly how I would, so optimizing for that is an unrealistic goal.\n\nI see a lot of people ask whether they should use ",{"_key":1304,"_type":68,"marks":1305,"text":1307},"3ec6f752da041",[1306],"51b6fcf9a7d1","eslint",{"_key":1309,"_type":68,"marks":1310,"text":1251},"3ec6f752da042",[],{"_key":1312,"_type":68,"marks":1313,"text":1315},"3ec6f752da043",[1314],"e7a70232ca11","prettier",{"_key":1317,"_type":68,"marks":1318,"text":1319},"3ec6f752da044",[],". For me, they serve very different purposes and therefore should be used in conjunction. Eslint is a traditional linter most of the time. It's going to identify issues with your code that have less to do with style and more to do with correctness. For example, I use eslint with ",{"_key":1321,"_type":68,"marks":1322,"text":1324},"3ec6f752da045",[1323],"3f14e17dbae0","AirBNB",{"_key":1326,"_type":68,"marks":1327,"text":1328},"3ec6f752da046",[]," rules. With that configuration, the following code would force the linter to fail:",[1330,1332,1334],{"_key":1306,"_type":91,"href":1331,"reference":12},"https:\u002F\u002Fgithub.com\u002Feslint\u002Feslint",{"_key":1314,"_type":91,"href":1333,"reference":12},"https:\u002F\u002Fgithub.com\u002Fprettier\u002Fprettier",{"_key":1323,"_type":91,"href":1335,"reference":12},"https:\u002F\u002Fgithub.com\u002Fairbnb\u002Fjavascript",{"_key":1337,"_type":176,"code":1338,"markDefs":12},"d0a0d88b62b4","var fooVar = 3; \u002F\u002F airbnb rules forebid \"var\"",{"_key":1340,"_type":64,"children":1341,"markDefs":1353,"style":93},"df1bc2785084",[1342,1346,1349],{"_key":1343,"_type":68,"marks":1344,"text":1345},"df1bc27850840",[],"It should be pretty obvious how eslint adds value to your development cycle. In essence, it makes sure you follow the rules about what is and isn't good practice. Due to this, linters are inherently opinionated. As with all opinions, take it with a grain of salt. The linter can be wrong.\n\nPrettier is a code formatter. It is less concerned with correctness and far more worried about uniformity and consistency. Prettier isn't going to complain about using ",{"_key":1347,"_type":68,"marks":1348,"text":578},"df1bc27850841",[176],{"_key":1350,"_type":68,"marks":1351,"text":1352},"df1bc27850842",[],", but it will automatically align all the brackets in your code. In my personal development process, I always run prettier as the last step before pushing code to Git. In many cases, it even makes sense to have Prettier run automatically on each commit to a repo. This ensures that all code coming into source control has consistent style and structure.\n",[],{"_key":1355,"_type":64,"children":1356,"markDefs":1361,"style":121},"65729c484132",[1357],{"_key":1358,"_type":68,"marks":1359,"text":1360},"65729c4841320",[],"\nTest Your Code",[],{"_key":1363,"_type":64,"children":1364,"markDefs":1369,"style":93},"e3cf269fe896",[1365],{"_key":1366,"_type":68,"marks":1367,"text":1368},"e3cf269fe8960",[],"Writing tests is an indirect but incredibly effective method of improving the JS code you write. I recommend becoming comfortable with a wide array of testing tools. Your testing needs will vary, and there's no single tool that can handle everything. There are tons of well established testing tools in the JS ecosystem, so choosing tools mostly comes down to personal taste. As always, think for yourself.",[],{"_key":1371,"_type":64,"children":1372,"markDefs":1383,"style":165},"3ca4b7077f52",[1373,1376,1380],{"_key":1374,"_type":68,"marks":1375,"text":566},"3ca4b7077f520",[],{"_key":1377,"_type":68,"marks":1378,"text":1379},"3ca4b7077f521",[159],"Test Driver - Ava",{"_key":1381,"_type":68,"marks":1382,"text":155},"3ca4b7077f522",[],[],{"_key":1385,"_type":176,"code":1386,"markDefs":12},"1b4bc7e96838","\nAvaJS on Github\n",{"_key":1388,"_type":64,"children":1389,"markDefs":1398,"style":93},"5b77857ca6f3",[1390,1394],{"_key":1391,"_type":68,"marks":1392,"text":1393},"5b77857ca6f30",[70],"Test drivers are simply frameworks that give structure and utilities at a very high level. They are often used in conjunction with other specific testing tools, which vary based on your testing needs.",{"_key":1395,"_type":68,"marks":1396,"text":1397},"5b77857ca6f31",[],"\n\nAva is the right balance of expressiveness and conciseness. Ava's parallel, and isolated architecture is the source of most of my love. Tests that run faster save developers time and companies money. Ava boasts a ton of nice features, such as built-in assertions, while managing to stay very minimal.\n\nAlternatives: Jest, Mocha, Jasmine",[],{"_key":1400,"_type":64,"children":1401,"markDefs":1412,"style":165},"41db9e2ed0e6",[1402,1405,1409],{"_key":1403,"_type":68,"marks":1404,"text":566},"41db9e2ed0e60",[],{"_key":1406,"_type":68,"marks":1407,"text":1408},"41db9e2ed0e61",[159],"Spies and Stubs - Sinon",{"_key":1410,"_type":68,"marks":1411,"text":155},"41db9e2ed0e62",[],[],{"_key":1414,"_type":64,"children":1415,"markDefs":1427,"style":93},"ccaca18bee6f",[1416,1419,1424],{"_key":1417,"_type":68,"marks":1418,"text":155},"ccaca18bee6f0",[],{"_key":1420,"_type":68,"marks":1421,"text":1423},"ccaca18bee6f1",[1422],"107ebc1d37d6","Sinon on Github",{"_key":1425,"_type":68,"marks":1426,"text":155},"ccaca18bee6f2",[],[1428],{"_key":1422,"_type":91,"href":1429,"reference":12},"https:\u002F\u002Fgithub.com\u002Fsinonjs\u002Fsinon",{"_key":1431,"_type":64,"children":1432,"markDefs":1441,"style":93},"ff64e4d0494a",[1433,1437],{"_key":1434,"_type":68,"marks":1435,"text":1436},"ff64e4d0494a0",[70],"Spies give us function analytics, such as how many times a function was called, what they were called by, and other insightful data.",{"_key":1438,"_type":68,"marks":1439,"text":1440},"ff64e4d0494a1",[],"\n\nSinon is a library that does a lot of things, but only a few super well. Specifically, sinon excels when it comes to spies and stubs. The feature set is rich but the syntax is concise. This is especially important for stubs, considering they partially exist to save space.\n\nAlternatives: testdouble",[],{"_key":1443,"_type":64,"children":1444,"markDefs":1455,"style":165},"087c613c015f",[1445,1448,1452],{"_key":1446,"_type":68,"marks":1447,"text":566},"087c613c015f0",[],{"_key":1449,"_type":68,"marks":1450,"text":1451},"087c613c015f1",[159],"Mocks - Nock",{"_key":1453,"_type":68,"marks":1454,"text":155},"087c613c015f2",[],[],{"_key":1457,"_type":64,"children":1458,"markDefs":1483,"style":93},"27d27ea6501f",[1459,1464,1467,1471,1475,1479],{"_key":1460,"_type":68,"marks":1461,"text":1463},"27d27ea6501f0",[1462],"8a6460031e7e","Nock on Github",{"_key":1465,"_type":68,"marks":1466,"text":566},"27d27ea6501f1",[],{"_key":1468,"_type":68,"marks":1469,"text":1470},"27d27ea6501f2",[70],"HTTP mocking is the process of faking some part of the http request process so the tester can inject custom logic to simulate server behavior.",{"_key":1472,"_type":68,"marks":1473,"text":1474},"27d27ea6501f3",[],"\n\nHttp mocking can be a real pain, but nock makes it less painful. Nock directly overrides the ",{"_key":1476,"_type":68,"marks":1477,"text":1478},"27d27ea6501f4",[176],"request",{"_key":1480,"_type":68,"marks":1481,"text":1482},"27d27ea6501f5",[]," built-in of nodejs and intercepts outgoing http requests. This in turn gives you complete control of the response.\n\nAlternatives: I don't really know of any :(",[1484],{"_key":1462,"_type":91,"href":1485,"reference":12},"https:\u002F\u002Fgithub.com\u002Fnock\u002Fnock?source=post_page---------------------------",{"_key":1487,"_type":64,"children":1488,"markDefs":1496,"style":165},"9fb3e9fc11ce",[1489,1492],{"_key":1490,"_type":68,"marks":1491,"text":566},"9fb3e9fc11ce0",[],{"_key":1493,"_type":68,"marks":1494,"text":1495},"9fb3e9fc11ce1",[159],"Web Automation - Selenium",[],{"_key":1498,"_type":64,"children":1499,"markDefs":1509,"style":93},"8c4c8ac4bdcb",[1500,1505],{"_key":1501,"_type":68,"marks":1502,"text":1504},"8c4c8ac4bdcb0",[1503],"63827c1a8f23","Selenium on Github",{"_key":1506,"_type":68,"marks":1507,"text":1508},"8c4c8ac4bdcb1",[],"\n\nI have mixed emotions about recommending Selenium. As it's the most popular option for web automation, it has a massive community and online resource set. Unfortunately, the learning curve is pretty steep, and it depends on a lot of external libraries for real use. That being said, it's the only real free option, so unless you're doing some enterprise grade web-automation, Selenium will do the job.\n\nAlternatives: Cypress, PhantomJS\n",[1510],{"_key":1503,"_type":91,"href":1511,"reference":12},"https:\u002F\u002Fgithub.com\u002FSeleniumHQ\u002Fselenium",{"_key":1513,"_type":64,"children":1514,"markDefs":1519,"style":121},"d463d50de112",[1515],{"_key":1516,"_type":68,"marks":1517,"text":1518},"d463d50de1120",[],"\nThe Never Ending Journey",[],{"_key":1521,"_type":64,"children":1522,"markDefs":1549,"style":93},"0c61fbdc4c84",[1523,1527,1531,1536,1540,1545],{"_key":1524,"_type":68,"marks":1525,"text":1526},"0c61fbdc4c840",[],"As with most things, writing better JavaScript is a continuous process. Code can always be cleaner, new features are added all the time, and there's never enough tests. It may seem overwhelming, but because there are so many potential aspects to improve, you can really progress at your own pace. Take things one step at a time, and before you know it, you'll be a JavaScript ace.\n\n",{"_key":1528,"_type":68,"marks":1529,"text":1530},"0c61fbdc4c841",[70],"This blog post originally appeared on Ryland’s ",{"_key":1532,"_type":68,"marks":1533,"text":1535},"0c61fbdc4c842",[1534,70],"c03485105b3e","personal website",{"_key":1537,"_type":68,"marks":1538,"text":1539},"0c61fbdc4c843",[70]," and on ",{"_key":1541,"_type":68,"marks":1542,"text":1544},"0c61fbdc4c844",[1543,70],"0ed028ce8fbe","Dev.to",{"_key":1546,"_type":68,"marks":1547,"text":1548},"0c61fbdc4c845",[70],". You can find more of his writing on both sites. If you would like to contribute articles to the Stack Overflow blog, send an email to pitches@stackoverflow.com.",[1550,1552],{"_key":1534,"_type":91,"href":1551,"reference":12},"https:\u002F\u002Fwww.cdevn.com\u002F",{"_key":1543,"_type":91,"href":1553,"reference":12},"https:\u002F\u002Fdev.to\u002Ftaillogs",true,"2019\u002F09\u002F12","There are lots of simple things you can do to improve at JavaScript. Here are some methods we use to write better JS.",{"_type":53,"asset":1558},{"_ref":1559,"_type":56},"image-eb9774ecfc0d05e8099ed26ee95a02c283b79b8a-630x450-png",{"code":1561,"language":1562},"\u003C!-- wp:separator -->\n\u003Chr class=\"wp-block-separator\"\u002F>\n\u003C!-- \u002Fwp:separator -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Cem>In our 2019 Dev Survey, we asked what kind of content Stack Overflow users would like to see beyond questions and answers. The most \u003Ca href=\"https:\u002F\u002Finsights.stackoverflow.com\u002Fsurvey\u002F2019#community-_-opinions-on-new-content-types\">popular response\u003C\u002Fa> was “tech articles written by other developers.” So from now on we'll be regularly publishing articles from contributors. \u003C\u002Fem>If  \u003Cem>you have an idea and would like to submit a pitch, you can email pitches@stackoverflow.com. \u003C\u002Fem>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:separator -->\n\u003Chr class=\"wp-block-separator\"\u002F>\n\u003C!-- \u002Fwp:separator -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Cbr>Hey there, I'm Ryland Goldstein, a product guy working on \u003Ca href=\"https:\u002F\u002Fblog.binaris.com\u002Fa-shift-in-thinking\u002F\">Reshuffle over at Binaris\u003C\u002Fa>. This is my second piece for Stack Overflow. Let's dig in! \u003Cbr>\u003Cbr>I don't see enough people talking about practical ways to improve at JavaScript. Here are some of the top methods I use to write better JS.\u003Cbr>\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading -->\n\u003Ch2>\u003Cspan style=\"text-decoration: underline;\">Use TypeScript\u003C\u002Fspan>\u003C\u002Fh2>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>The number one thing you can do to improve your JS is by not writing JS. For the uninitiated, \u003Ca href=\"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMicrosoft_TypeScript\">TypeScript (TS)\u003C\u002Fa> is a \"compiled\" superset of JS (anything that runs in JS runs in TS). TS adds a comprehensive optional typing system on top of the vanilla JS experience. For a long time, TS support across the ecosystem was inconsistent enough for me to feel uncomfortable recommending it. Thankfully, those days are long behind us and most frameworks support TS out of the box. Now that we're all on the same page about what TS \u003Cem>is\u003C\u002Fem>, let's talk about why you would want to use it.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cbr>\u003Cstrong>TypeScript enforces type safety\u003C\u002Fstrong>\u003Cbr>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Type safety describes a process where a compiler verifies that all types are being used in a legal way throughout a piece of code. In other words, if you create a function \u003Ccode>foo\u003C\u002Fcode> that takes a number:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>function foo(someNum: number): number {\n  return someNum + 5;\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>That \u003Ccode>foo\u003C\u002Fcode> function should only ever be called with a number:\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cem>good\u003C\u002Fem>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>console.log(foo(2)); \u002F\u002F prints \"7\"\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cem>no good\u003C\u002Fem>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>console.log(foo(\"two\")); \u002F\u002F invalid TS code\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Aside from the overhead of adding types to your code, there are zero downsides to type-safety enforcement. The benefit on the other hand, is too large to ignore. Type safety provides an extra level of protection against common errors\u002Fbugs, which is a blessing for a lawless language like JS.\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cstrong>Typescript types make refactoring larger applications possible\u003C\u002Fstrong>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Refactoring a large JS application can be a true nightmare. Most of the pain of refactoring JS is due to the fact that it doesn't enforce function signatures. This means a JS function can never really be misused. For example, if I have a function \u003Ccode>myAPI\u003C\u002Fcode> that is used by 1000 different services:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>function myAPI(someNum, someString) {\n  if (someNum > 0) {\n    leakCredentials();\n  } else {\n    console.log(someString);\n  }\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>and I change the call signature a bit:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>function myAPI(someString, someNum) {\n  if (someNum > 0) {\n    leakCredentials();\n  } else {\n    console.log(someString);\n  }\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>I have to be 100% certain, that every place where this function is used (thousands of places), I correctly update the usage. If I even miss one my credentials could leak. Here's the same scenario with TS:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cem>before\u003C\u002Fem>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>function myAPITS(someNum: number, someString: string) { ... }\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cem>after\u003C\u002Fem>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>function myAPITS(someString: string, someNum: number) { ... }\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>As you can see, the \u003Ccode>myAPITS\u003C\u002Fcode> function went through the same change as the JavaScript counterpart. But instead of resulting in valid JavaScript, this code results in invalid TypeScript, as the thousands of places it's used are now providing the wrong types. And because of the type safety we discussed earlier, those thousand cases will block compilation and your credentials won't get leaked (that's always nice).\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cbr>\u003Cstrong>TypeScript makes team architecture communication easier\u003C\u002Fstrong>\u003Cbr>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>When TS is setup correctly, it will be difficult to write code without first defining your interfaces and classes. This provides a way to share concise, communicative architecture proposals. Before TS, other solutions to this problem existed, but none solved it natively without making you do extra work. For example, if I want to propose a new \u003Ccode>Request\u003C\u002Fcode> type for my backend, I can send the following to a teammate using TS.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>interface BasicRequest {\n  body: Buffer;\n  headers: { [header: string]: string | string[] | undefined; };\n  secret: Shhh;\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>I already had to write the code, but now I can share my incremental progress and get feedback without investing more time. I don't know if TS is inherently less bug-prone than JS. I do strongly believe that forcing developers to define interfaces and APIs first results in better code.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Overall, TS has evolved into a mature and more predictable alternative to vanilla JS. Developers definitely still need to be comfortable with vanilla JS, but most new projects I start these days are TS from the outset.\u003Cbr>\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:image {\"id\":11751,\"align\":\"center\",\"linkDestination\":\"custom\"} -->\n\u003Cdiv class=\"wp-block-image\">\u003Cfigure class=\"aligncenter\">\u003Ca href=\"https:\u002F\u002Fstackoverflow.com\u002Fjobs?r=true?utm_source=so-owned&amp;utm_medium=blog&amp;utm_campaign=jobs2019&amp;utm_content=pjs\">\u003Cimg src=\"https:\u002F\u002Fstackoverflow.blog\u002Fwp-content\u002Fuploads\u002F2018\u002F04\u002FAd-4-Sidebar@2x-.png\" alt=\"\" class=\"wp-image-11751\"\u002F>\u003C\u002Fa>\u003C\u002Ffigure>\u003C\u002Fdiv>\n\u003C!-- \u002Fwp:image -->\n\n\u003C!-- wp:heading -->\n\u003Ch2>\u003Cbr>\u003Cspan style=\"text-decoration: underline;\">Use Modern Features\u003C\u002Fspan>\u003C\u002Fh2>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>JavaScript is one of the most popular (if not the most) programming languages in the world. You might expect that a 20+ year old language used by hundreds of millions of people would be mostly figured out by now, but the opposite is actually true. In recent times, many changes and additions have been made to JS (yes I know, technically ECMAScript), fundamentally morphing the developer experience. As someone who only started writing JS in the last two years, I had the advantage of coming in without bias or expectations. This resulted in much more pragmatic choices about what features of the language to utilize and which to avoid.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cbr>\u003Cstrong>\u003Ccode>async\u003C\u002Fcode> and \u003Ccode>await\u003C\u002Fcode>\u003C\u002Fstrong>\u003Cbr>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>For a long time, asynchronous, event-driven callbacks were a unavoidable part of JS development:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cem>traditional callback\u003C\u002Fem>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>makeHttpRequest('google.com', function (err, result) {\n  if (err) {\n    console.log('Oh boy, an error');\n  } else {\n    console.log(result);\n  }\n});\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>I'm not going to spend time explaining why the above is problematic (\u003Ca href=\"http:\u002F\u002Fcdevn.com\u002Fparallel-computing-simplified-starring-gordon-ramsay\">but I have before\u003C\u002Fa>). To solve the issue with callbacks, a new concept—Promises—were added to JS. Promises allow you to write asynchronous logic while avoiding the nesting issues that previously plagued callback-based code.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cem>Promises\u003C\u002Fem>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>makeHttpRequest('google.com').then(function (result) {\n  console.log(result);\n}).catch(function (err) {\n  console.log('Oh boy, an error');\n});\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>The biggest advantage of Promises over callbacks is readability and chainability.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>While Promises are great, they still left something to be desired. For many, the Promise experience was still too reminiscent of callbacks. Specifically, developers were asking for an alternative to the Promise model. To remedy this, the ECMAScript committee decided to add a new method of utilizing promises, \u003Ccode>async\u003C\u002Fcode> and \u003Ccode>await\u003C\u002Fcode>:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cbr>\u003Cem>\u003Ccode>async\u003C\u002Fcode> and \u003Ccode>await\u003C\u002Fcode>\u003C\u002Fem>\u003Cbr>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>try {\n  const result = await makeHttpRequest('google.com');\n  console.log(result);\n} catch (err) {\n  console.log('Oh boy, an error');\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>The one caveat being, anything you \u003Ccode>await\u003C\u002Fcode> must have been declared \u003Ccode>async\u003C\u002Fcode>:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cem>required definition of makeHttpRequest in prev example\u003C\u002Fem>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>async function makeHttpRequest(url) {\n  \u002F\u002F ...\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>It's also possible to \u003Ccode>await\u003C\u002Fcode> a Promise directly since an \u003Ccode>async\u003C\u002Fcode> function is really just a fancy Promise wrapper. This also means the \u003Ccode>async\u002Fawait\u003C\u002Fcode> code and the Promise code are functionally equivalent. So feel free to use \u003Ccode>async\u002Fawait\u003C\u002Fcode> without feeling guilty.\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cbr>\u003Cstrong>\u003Ccode>let\u003C\u002Fcode> and \u003Ccode>const\u003C\u002Fcode>\u003C\u002Fstrong>\u003Cbr>\u003Cbr>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>For most of JS's existence, there was only one variable scope qualifier: \u003Ccode>var\u003C\u002Fcode>. \u003Ccode>var\u003C\u002Fcode> has some pretty unique\u002Finteresting rules in regards to how it handles scope. The scoping behavior of \u003Ccode>var\u003C\u002Fcode> is inconsistent and confusing and has resulted in unexpected behavior and therefore bugs throughout the lifetime of JS. But as of ES6, there is an alternative to \u003Ccode>var\u003C\u002Fcode>: \u003Ccode>const\u003C\u002Fcode> and \u003Ccode>let\u003C\u002Fcode>. There is practically zero need to use \u003Ccode>var\u003C\u002Fcode> anymore, so don't. Any logic that uses \u003Ccode>var\u003C\u002Fcode> can always be converted to equivalent \u003Ccode>const\u003C\u002Fcode> and \u003Ccode>let\u003C\u002Fcode> based code.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>As for when to use \u003Ccode>const\u003C\u002Fcode> vs \u003Ccode>let\u003C\u002Fcode>, I always start by declaring everything \u003Ccode>const\u003C\u002Fcode>. \u003Ccode>const\u003C\u002Fcode> is far more restrictive and \"immutablish,\" which usually results in better code. There aren't a ton of \"real scenarios\" where using \u003Ccode>let\u003C\u002Fcode> is necessary, I would say 1\u002F20 variables I declare with \u003Ccode>let\u003C\u002Fcode>. The rest are all \u003Ccode>const\u003C\u002Fcode>.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>I said \u003Ccode>const\u003C\u002Fcode> is \"immutablish\" because it does not work in the same way as \u003Ccode>const\u003C\u002Fcode> in C\u002FC++. What \u003Ccode>const\u003C\u002Fcode> means to the JavaScript runtime is that the reference to that \u003Ccode>const\u003C\u002Fcode> variable will never change. This does not mean the contents stored at that reference will never change. For primitive types (number, boolean, etc.), \u003Ccode>const\u003C\u002Fcode> does translate to immutability (because it's a single memory address). But for all objects (classes, arrays, dicts), \u003Ccode>const\u003C\u002Fcode> does not guarantee immutability.\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cbr>\u003Cbr>\u003Cstrong>Arrow \u003Ccode>=&gt;\u003C\u002Fcode> Functions\u003C\u002Fstrong>\u003Cbr>\u003Cbr>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Arrow functions are a concise method of declaring \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FFunctions\u002FArrow_functions\">anonymous functions\u003C\u002Fa> in JS. Anonymous functions describe functions that aren't explicitly named. Usually, anonymous functions are passed as a callback or event hook.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cbr>\u003Cem>vanilla anonymous function\u003C\u002Fem>\u003Cbr>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>someMethod(1, function () { \u002F\u002F has no name\n  console.log('called');\n});\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>For the most part, there isn't anything \"wrong\" with this style. Vanilla anonymous functions behave \"interestingly\" in regards to scope, which can\u002Fhas resulted in many unexpected bugs. We don't have to worry about that anymore thanks to arrow functions. Here is the same code implemented with an arrow function:\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cem>anonymous arrow function\u003C\u002Fem>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>someMethod(1, () => { \u002F\u002F has no name\n  console.log('called');\n});\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Aside from being far more concise, arrow functions have much more practical scoping behavior. Arrow functions inherit \u003Ccode>this\u003C\u002Fcode> from the scope they were defined in.\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>In some cases, arrow functions can be even more concise:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>const added = [0, 1, 2, 3, 4].map((item) => item + 1);\nconsole.log(added) \u002F\u002F prints \"[1, 2, 3, 4, 5]\"\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Arrow functions that reside on a single line include a implicit \u003Ccode>return\u003C\u002Fcode> statement. There is no need for brackets or semi-colons with single line arrow functions.\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>I want to make it clear. This isn't a \u003Ccode>var\u003C\u002Fcode> situation; there are still valid use cases for vanilla anonymous functions (specifically class methods). That being said, I've found that if you always default to an arrow function, you end up doing a lot less debugging as opposed to defaulting to vanilla anonymous functions.\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FFunctions\u002FArrow_functions\">As usual, the Mozilla docs are the best resource\u003C\u002Fa>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cbr>\u003Cbr>\u003Cstrong>Spread Operator \u003Ccode>...\u003C\u002Fcode>\u003C\u002Fstrong>\u003Cbr>\u003Cbr>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Extracting key\u002Fvalue pairs of one object and adding them as children of another object is a very common scenario. Historically, there have been a few ways to accomplish this, but all of those methods are pretty clunky:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>const obj1 = { dog: 'woof' };\nconst obj2 = { cat: 'meow' };\nconst merged = Object.assign({}, obj1, obj2);\nconsole.log(merged) \u002F\u002F prints { dog: 'woof', cat: 'meow' }\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>This pattern is incredibly common, so the above approach quickly becomes tedious. Thanks to the spread operator, there's never a need to use it again:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>const obj1 = { dog: 'woof' };\nconst obj2 = { cat: 'meow' };\nconsole.log({ ...obj1, ...obj2 }); \u002F\u002F prints { dog: 'woof', cat: 'meow' }\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>The great part is, this also works seamlessly with arrays:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>const arr1 = [1, 2];\nconst arr2 = [3, 4];\nconsole.log([ ...arr1, ...arr2 ]); \u002F\u002F prints [1, 2, 3, 4]\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>It's probably not the most important recent JS feature, but it's one of my favorites.\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cbr>\u003Cbr>\u003Cstrong>Template Literals (Template Strings)\u003C\u002Fstrong>\u003Cbr>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Strings are one of the most common programming constructs. This is why it's so embarrassing that natively declaring strings is still poorly supported in many languages. For a long time, JS was in the \"crappy string\" family. But the addition of template literals put JS in a category of its own. Template literals natively and conveniently solve the two biggest problems with writing strings: adding dynamic content and writing strings that bridge multiple lines:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>const name = 'Ryland';\nconst helloString =\n`Hello\n ${name}`;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>I think the code speaks for itself. What an amazing implementation.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cbr>\u003Cbr>\u003Cstrong>Object Destructuring\u003C\u002Fstrong>\u003Cbr>\u003Cbr>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Object destructuring is a way to extract values from a data collection (object, array, etc.), without having to iterate over the data or access its keys explicitly:\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cem>old way\u003C\u002Fem>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>function animalParty(dogSound, catSound) {}\n\nconst myDict = {\n  dog: 'woof',\n  cat: 'meow',\n};\n\nanimalParty(myDict.dog, myDict.cat);\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Cem>destructuring\u003C\u002Fem>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>function animalParty(dogSound, catSound) {}\n\nconst myDict = {\n  dog: 'woof',\n  cat: 'meow',\n};\n\nconst { dog, cat } = myDict;\nanimalParty(dog, cat);\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>But wait, there's more. You can also define destructuring in the signature of a function:\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cem>destructuring 2\u003C\u002Fem>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>function animalParty({ dog, cat }) {}\n\nconst myDict = {\n  dog: 'woof',\n  cat: 'meow',\n};\n\nanimalParty(myDict);\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>It also works with arrays:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cem>destructuring 3\u003C\u002Fem>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>[a, b] = [10, 20];\n\nconsole.log(a); \u002F\u002F prints 10\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>There are a ton of other modern features you should be utilizing. Here are a handful of others that stand out to me:\u003Cbr>\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:list -->\n\u003Cul>\u003Cli>\u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FFunctions\u002Frest_parameters\">Rest Parameter\u003C\u002Fa>\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FStatements\u002Fimport\">Import Over Require\u003C\u002Fa>\u003C\u002Fli>\u003Cli>\u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FArray\u002Ffind\">Array Element Find\u003C\u002Fa>\u003C\u002Fli>\u003C\u002Ful>\n\u003C!-- \u002Fwp:list -->\n\n\u003C!-- wp:heading -->\n\u003Ch2>\u003Cspan style=\"text-decoration: underline;\">Always Assume Your System is Distributed\u003C\u002Fspan>\u003C\u002Fh2>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>When writing parallelized applications your goal is to optimize the amount of work you're doing at one time. If you have four available cores and your code can only utilize a single core, 75% of your potential is being wasted. This means blocking, synchronous operations are the ultimate enemy of parallel computing. But considering that JS is a single threaded language, things don't run on multiple cores. So what's the point?\u003Cbr>\u003Cbr>JS is single threaded, but not single-file (as in lines at school). Even though it isn't parallel, it's still concurrent. Sending an HTTP request may take seconds or even minutes, so if JS stopped executing code until a response came back from the request, the language would be unusable.\u003Cbr>\u003Cbr>JavaScript solves this with an \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FEventLoop\">event loop\u003C\u002Fa>. The event loop loops through registered events and executes them based on internal scheduling\u002Fprioritization logic. This is what enables sending thousands of simultaneous HTTP requests or reading multiple files from disk at the same time. Here's the catch: JavaScript can only utilize this capability if you utilize the correct features. The most simple example is the for-loop:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>let sum = 0;\nconst myArray = [1, 2, 3, 4, 5, ... 99, 100];\nfor (let i = 0; i &lt; myArray.length; i += 1) {\n  sum += myArray[i];\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>A vanilla for-loop is one of the least parallel constructs that exists in programming. At my last job, I led a team that spent months attempting to convert traditional \u003Ccode>R\u003C\u002Fcode> lang for-loops into automagically parallel code. It's basically an impossible problem, only solvable by waiting for deep learning to improve. The difficulty of parallelizing a for-loop stems from a few problematic patterns. Sequential for-loops are very rare, but they alone make it impossible to guarantee a for-loops decomposability:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>let runningTotal = 0;\nfor (let i = 0; i &lt; myArray.length; i += 1) {\n  if (i === 50 &amp;&amp; runningTotal > 50) {\n    runningTotal = 0;\n  }\n  runningTotal += Math.random() + runningTotal;\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>This code only produces the intended result if it is executed in order, iteration by iteration. If you tried to execute multiple iterations at once, the processor might incorrectly branch based on inaccurate values, which invalidates the result. We would be having a different conversation if this was C code, as the usage is different and there are quite a few tricks the compiler can do with loops. In JavaScript, traditional for-loops should only be used if absolutely necessary. Otherwise, utilize the following constructs:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Cbr>\u003Cbr>\u003Cem>map\u003C\u002Fem>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>\u002F\u002F in decreasing relevancy :0\nconst urls = ['google.com', 'yahoo.com', 'aol.com', 'netscape.com'];\nconst resultingPromises = urls.map((url) => makHttpRequest(url));\nconst results = await Promise.all(resultingPromises);\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Cem>map with index\u003C\u002Fem>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>\u002F\u002F in decreasing relevancy :0\nconst urls = ['google.com', 'yahoo.com', 'aol.com', 'netscape.com'];\nconst resultingPromises = urls.map((url, index) => makHttpRequest(url, index));\nconst results = await Promise.all(resultingPromises);\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Cem>for-each\u003C\u002Fem>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>const urls = ['google.com', 'yahoo.com', 'aol.com', 'netscape.com'];\n\u002F\u002F note this is non blocking\nurls.forEach(async (url) => {\n  try {\n    await makHttpRequest(url);\n  } catch (err) {\n    console.log(`${err} bad practice`);\n  }\n});\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>I'll explain why these are an improvement over traditional for-loops. Instead of executing each iteration in order (sequentially), constructs such as \u003Ccode>map\u003C\u002Fcode> take all of the elements and submit them as individual events to the user-defined map function. For the most part, individual iterations have no inherent connection or dependence to each other, allowing them to run concurrently. This isn't to say that you couldn't accomplish the same thing with for-loops. In fact, it would look something like this:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>const items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\nasync function testCall() {\n  \u002F\u002F do async stuff here\n}\n\nfor (let i = 0; i &lt; 10; i += 1) {\n  testCall();\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>As you can see, the for-loop doesn't prevent me from doing it the right way, but it sure doesn't make it any easier either. Compare to the map version:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>const items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\nitems.map(async (item) => {\n \u002F\u002F do async stuff here\n});\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>As you can see, the \u003Ccode>map\u003C\u002Fcode> just works. The advantage of the map becomes even more clear if you want to block until all of the individual async operations are done. With the for-loop code, you would need to manage an array yourself. Here's the \u003Ccode>map\u003C\u002Fcode> version:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>const items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n const allResults = await Promise.all(items.map(async (item) => {\n  \u002F\u002F do async stuff here\n }));\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cbr>\u003Cem>it's really that easy\u003C\u002Fem>\u003Cbr>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>There are many cases where a for-loop would be just as performant (or maybe more) in comparison to a \u003Ccode>map\u003C\u002Fcode> or \u003Ccode>forEach\u003C\u002Fcode>. I would still argue that losing a few cycles now is worth the advantage of using a well defined API. That way, any future improvements to that data access patterns implementation will benefit your code. The for-loop is too generic to have meaningful optimizations for that same pattern.\u003Cbr>\u003Cbr>\u003Cem>There are a other valid async options outside of \u003Ccode>map\u003C\u002Fcode> and \u003Ccode>forEach\u003C\u002Fcode>, such as \u003Ccode>for-await-of\u003C\u002Fcode>.\u003C\u002Fem>\u003Cbr>\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading -->\n\u003Ch2>\u003Cspan style=\"text-decoration: underline;\">Lint Your Code and Enforce a Style\u003C\u002Fspan>\u003C\u002Fh2>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Code without a consistent style (look and feel) is incredibly difficult to read and understand. Therefore, a critical aspect of writing high-end code in any language is having a consistent and sensible style. Due to the breadth of the JS ecosystem, there are a LOT of options for linters and style specifics. What I can't stress enough is that it's far more important that you are using a linter and enforcing a style (any of them) than it is which linter\u002Fstyle you specifically choose. At the end of the day, no one is going to write code exactly how I would, so optimizing for that is an unrealistic goal.\u003Cbr>\u003Cbr>I see a lot of people ask whether they should use \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Feslint\u002Feslint\">eslint\u003C\u002Fa> or \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fprettier\u002Fprettier\">prettier\u003C\u002Fa>. For me, they serve very different purposes and therefore should be used in conjunction. Eslint is a traditional linter most of the time. It's going to identify issues with your code that have less to do with style and more to do with correctness. For example, I use eslint with \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fairbnb\u002Fjavascript\">AirBNB\u003C\u002Fa> rules. With that configuration, the following code would force the linter to fail:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>var fooVar = 3; \u002F\u002F airbnb rules forebid \"var\"\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>It should be pretty obvious how eslint adds value to your development cycle. In essence, it makes sure you follow the rules about what is and isn't good practice. Due to this, linters are inherently opinionated. As with all opinions, take it with a grain of salt. The linter can be wrong.\u003Cbr>\u003Cbr>Prettier is a code formatter. It is less concerned with correctness and far more worried about uniformity and consistency. Prettier isn't going to complain about using \u003Ccode>var\u003C\u002Fcode>, but it will automatically align all the brackets in your code. In my personal development process, I always run prettier as the last step before pushing code to Git. In many cases, it even makes sense to have Prettier run automatically on each commit to a repo. This ensures that all code coming into source control has consistent style and structure.\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading -->\n\u003Ch2>\u003Cbr>\u003Cspan style=\"text-decoration: underline;\">Test Your Code\u003C\u002Fspan>\u003C\u002Fh2>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Writing tests is an indirect but incredibly effective method of improving the JS code you write. I recommend becoming comfortable with a wide array of testing tools. Your testing needs will vary, and there's no single tool that can handle everything. There are tons of well established testing tools in the JS ecosystem, so choosing tools mostly comes down to personal taste. As always, think for yourself.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cbr>\u003Cbr>\u003Cstrong>Test Driver - Ava\u003C\u002Fstrong>\u003Cbr>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:verse -->\n\u003Cpre class=\"wp-block-verse\">\u003Cbr>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Favajs\">AvaJS on Github\u003C\u002Fa>\u003Cbr>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:verse -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Cem>Test drivers are simply frameworks that give structure and utilities at a very high level. They are often used in conjunction with other specific testing tools, which vary based on your testing needs.\u003C\u002Fem>\u003Cbr>\u003Cbr>Ava is the right balance of expressiveness and conciseness. Ava's parallel, and isolated architecture is the source of most of my love. Tests that run faster save developers time and companies money. Ava boasts a ton of nice features, such as built-in assertions, while managing to stay very minimal.\u003Cbr>\u003Cbr>Alternatives: Jest, Mocha, Jasmine\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cbr>\u003Cbr>\u003Cstrong>Spies and Stubs - Sinon\u003C\u002Fstrong>\u003Cbr>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Cbr>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fsinonjs\u002Fsinon\">Sinon on Github\u003C\u002Fa>\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Cem>Spies give us function analytics, such as how many times a function was called, what they were called by, and other insightful data.\u003C\u002Fem>\u003Cbr>\u003Cbr>Sinon is a library that does a lot of things, but only a few super well. Specifically, sinon excels when it comes to spies and stubs. The feature set is rich but the syntax is concise. This is especially important for stubs, considering they partially exist to save space.\u003Cbr>\u003Cbr>Alternatives: testdouble\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cbr>\u003Cbr>\u003Cstrong>Mocks - Nock\u003C\u002Fstrong>\u003Cbr>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fnock\u002Fnock?source=post_page---------------------------\">Nock on Github\u003C\u002Fa>\u003Cbr>\u003Cbr>\u003Cem>HTTP mocking is the process of faking some part of the http request process so the tester can inject custom logic to simulate server behavior.\u003C\u002Fem>\u003Cbr>\u003Cbr>Http mocking can be a real pain, but nock makes it less painful. Nock directly overrides the \u003Ccode>request\u003C\u002Fcode> built-in of nodejs and intercepts outgoing http requests. This in turn gives you complete control of the response.\u003Cbr>\u003Cbr>Alternatives: I don't really know of any :(\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3>\u003Cbr>\u003Cbr>\u003Cstrong>Web Automation - Selenium\u003C\u002Fstrong>\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FSeleniumHQ\u002Fselenium\">Selenium on Github\u003C\u002Fa>\u003Cbr>\u003Cbr>I have mixed emotions about recommending Selenium. As it's the most popular option for web automation, it has a massive community and online resource set. Unfortunately, the learning curve is pretty steep, and it depends on a lot of external libraries for real use. That being said, it's the only real free option, so unless you're doing some enterprise grade web-automation, Selenium will do the job.\u003Cbr>\u003Cbr>Alternatives: Cypress, PhantomJS\u003Cbr>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading -->\n\u003Ch2>\u003Cbr>\u003Cspan style=\"text-decoration: underline;\">The Never Ending Journey\u003C\u002Fspan>\u003C\u002Fh2>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>As with most things, writing better JavaScript is a continuous process. Code can always be cleaner, new features are added all the time, and there's never enough tests. It may seem overwhelming, but because there are so many potential aspects to improve, you can really progress at your own pace. Take things one step at a time, and before you know it, you'll be a JavaScript ace.\u003Cbr>\u003Cbr>\u003Cem>This blog post originally appeared on Ryland’s \u003C\u002Fem>\u003Ca href=\"https:\u002F\u002Fwww.cdevn.com\u002F\">\u003Cem>personal website\u003C\u002Fem>\u003C\u002Fa>\u003Cem> and on \u003C\u002Fem>\u003Ca href=\"https:\u002F\u002Fdev.to\u002Ftaillogs\">\u003Cem>Dev.to\u003C\u002Fem>\u003C\u002Fa>\u003Cem>. You can find more of his writing on both sites. If you would like to contribute articles to the Stack Overflow blog, send an email to pitches@stackoverflow.com.\u003C\u002Fem>\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:block {\"ref\":13752} \u002F-->","html","2019-09-12T14:58:46.000Z",{"current":1565},"practical-ways-to-write-better-javascript",[1567,1575,1577,1582,1586,1591,1593,1597],{"_createdAt":1568,"_id":1569,"_rev":1570,"_type":1571,"_updatedAt":1568,"slug":1572,"title":1574},"2023-05-23T16:43:21Z","wp-tagcat-bulletin","9HpbCsT2tq0xwozQfkc4ih","blogTag",{"current":1573},"bulletin","Bulletin",{"_createdAt":1568,"_id":1569,"_rev":1570,"_type":1571,"_updatedAt":1568,"slug":1576,"title":1574},{"current":1573},{"_createdAt":1568,"_id":1578,"_rev":1570,"_type":1571,"_updatedAt":1568,"slug":1579,"title":1581},"wp-tagcat-code-for-a-living",{"current":1580},"code-for-a-living","Code for a Living",{"_createdAt":1568,"_id":1583,"_rev":1570,"_type":1571,"_updatedAt":1568,"slug":1584,"title":1585},"wp-tagcat-javascript",{"current":1585},"javascript",{"_createdAt":1568,"_id":1587,"_rev":1570,"_type":1571,"_updatedAt":1568,"slug":1588,"title":1590},"wp-tagcat-stackoverflow",{"current":1589},"stackoverflow","Stackoverflow",{"_createdAt":1568,"_id":1587,"_rev":1570,"_type":1571,"_updatedAt":1568,"slug":1592,"title":1590},{"current":1589},{"_createdAt":1568,"_id":1594,"_rev":1570,"_type":1571,"_updatedAt":1568,"slug":1595,"title":1596},"wp-tagcat-typescript",{"current":1596},"typescript",{"_createdAt":1568,"_id":1598,"_rev":1570,"_type":1571,"_updatedAt":1568,"slug":1599,"title":1600},"wp-tagcat-programming",{"current":1600},"programming","Practical Ways to Write Better JavaScript",[1603,1609,1615,1621],{"_id":1604,"publishedAt":1605,"slug":1606,"sponsored":12,"title":1608},"76c9771b-34e6-4d98-8641-ecefc711f0ef","2026-07-06T15:23:34.559Z",{"_type":10,"current":1607},"when-the-sensor-starts-thinking-snortml-agentic-ai-and-the-evolving-architecture-of-intrusion-detection","When the sensor starts thinking: SnortML, agentic AI, and the evolving architecture of intrusion detection",{"_id":1610,"publishedAt":1611,"slug":1612,"sponsored":12,"title":1614},"28e560af-f0aa-4d46-bd90-f435ad604aa7","2026-06-26T14:00:27.102Z",{"_type":10,"current":1613},"paging-charity-how-can-engineering-leaders-avoid-becoming-bond-villains","Paging Charity! How can engineering leaders avoid becoming Bond villains?",{"_id":1616,"publishedAt":1617,"slug":1618,"sponsored":12,"title":1620},"4b22c2a3-3779-4966-93eb-5230391dbdce","2026-06-23T14:08:58.595Z",{"_type":10,"current":1619},"your-ai-shipped-a-backend-that-boots-that-is-the-whole-problem","Your AI shipped a backend that boots. That is the whole problem.",{"_id":1622,"publishedAt":1623,"slug":1624,"sponsored":12,"title":1626},"5cf362e1-fe7b-45af-b69c-914731c6a052","2026-06-23T14:00:00.000Z",{"_type":10,"current":1625},"the-2026-developer-survey-is-now-open-for-human-developers-only","The 2026 Developer Survey is now open (for human developers only)!",{"data":1628,"sourceMap":-1},{"count":1629,"lastTimestamp":1630},41,"2024-10-17T15:02:29Z"]