A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5 年之前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang=fr>
  4. <!-- Has to be within the first 1024 bytes, hence before the <title>
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset=utf-8>
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name=viewport content="width=device-width,minimum-scale=1,initial-scale=1,shrink-to-fit=no">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>Real-World JavaScript Anti-Patterns (Part One) (archive) — David Larlet</title>
  13. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  14. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons/apple-touch-icon.png">
  15. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons/favicon-32x32.png">
  16. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons/favicon-16x16.png">
  17. <link rel="manifest" href="/manifest.json">
  18. <link rel="mask-icon" href="/static/david/icons/safari-pinned-tab.svg" color="#5bbad5">
  19. <link rel="shortcut icon" href="/static/david/icons/favicon.ico">
  20. <meta name="apple-mobile-web-app-title" content="David Larlet">
  21. <meta name="application-name" content="David Larlet">
  22. <meta name="msapplication-TileColor" content="#da532c">
  23. <meta name="msapplication-config" content="/static/david/icons/browserconfig.xml">
  24. <meta name="theme-color" content="#f0f0ea">
  25. <!-- That good ol' feed, subscribe :p. -->
  26. <link rel=alternate type="application/atom+xml" title=Feed href="/david/log/">
  27. <meta name="robots" content="noindex, nofollow">
  28. <meta content="origin-when-cross-origin" name="referrer">
  29. <!-- Canonical URL for SEO purposes -->
  30. <link rel="canonical" href="http://blog.javascripting.com/2014/11/06/real-world-javascript-anti-patterns/">
  31. <style>
  32. /* http://meyerweb.com/eric/tools/css/reset/ */
  33. html, body, div, span,
  34. h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  35. a, abbr, address, big, cite, code,
  36. del, dfn, em, img, ins,
  37. small, strike, strong, tt, var,
  38. dl, dt, dd, ol, ul, li,
  39. fieldset, form, label, legend,
  40. table, caption, tbody, tfoot, thead, tr, th, td,
  41. article, aside, canvas, details, embed,
  42. figure, figcaption, footer, header, hgroup,
  43. menu, nav, output, ruby, section, summary,
  44. time, mark, audio, video {
  45. margin: 0;
  46. padding: 0;
  47. border: 0;
  48. font-size: 100%;
  49. font: inherit;
  50. vertical-align: baseline;
  51. }
  52. /* HTML5 display-role reset for older browsers */
  53. article, aside, details, figcaption, figure,
  54. footer, header, hgroup, menu, nav, section { display: block; }
  55. body { line-height: 1; }
  56. blockquote, q { quotes: none; }
  57. blockquote:before, blockquote:after,
  58. q:before, q:after {
  59. content: '';
  60. content: none;
  61. }
  62. table {
  63. border-collapse: collapse;
  64. border-spacing: 0;
  65. }
  66. /* http://practicaltypography.com/equity.html */
  67. /* https://calendar.perfplanet.com/2016/no-font-face-bulletproof-syntax/ */
  68. /* https://www.filamentgroup.com/lab/js-web-fonts.html */
  69. @font-face {
  70. font-family: 'EquityTextB';
  71. src: url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff2') format('woff2'),
  72. url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff') format('woff');
  73. font-weight: 300;
  74. font-style: normal;
  75. font-display: swap;
  76. }
  77. @font-face {
  78. font-family: 'EquityTextB';
  79. src: url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff2') format('woff2'),
  80. url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff') format('woff');
  81. font-weight: 300;
  82. font-style: italic;
  83. font-display: swap;
  84. }
  85. @font-face {
  86. font-family: 'EquityTextB';
  87. src: url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff2') format('woff2'),
  88. url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff') format('woff');
  89. font-weight: 700;
  90. font-style: normal;
  91. font-display: swap;
  92. }
  93. @font-face {
  94. font-family: 'ConcourseT3';
  95. src: url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff2') format('woff2'),
  96. url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff') format('woff');
  97. font-weight: 300;
  98. font-style: normal;
  99. font-display: swap;
  100. }
  101. /* http://practice.typekit.com/lesson/caring-about-opentype-features/ */
  102. body {
  103. /* http://www.cssfontstack.com/ Palatino 99% Win 86% Mac */
  104. font-family: "EquityTextB", Palatino, serif;
  105. background-color: #f0f0ea;
  106. color: #07486c;
  107. font-kerning: normal;
  108. -moz-osx-font-smoothing: grayscale;
  109. -webkit-font-smoothing: subpixel-antialiased;
  110. text-rendering: optimizeLegibility;
  111. font-variant-ligatures: common-ligatures contextual;
  112. font-feature-settings: "kern", "liga", "clig", "calt";
  113. }
  114. pre, code, kbd, samp, var, tt {
  115. font-family: 'TriplicateT4c', monospace;
  116. }
  117. em {
  118. font-style: italic;
  119. color: #323a45;
  120. }
  121. strong {
  122. font-weight: bold;
  123. color: black;
  124. }
  125. nav {
  126. background-color: #323a45;
  127. color: #f0f0ea;
  128. display: flex;
  129. justify-content: space-around;
  130. padding: 1rem .5rem;
  131. }
  132. nav:last-child {
  133. border-bottom: 1vh solid #2d7474;
  134. }
  135. nav a {
  136. color: #f0f0ea;
  137. }
  138. nav abbr {
  139. border-bottom: 1px dotted white;
  140. }
  141. h1 {
  142. border-top: 1vh solid #2d7474;
  143. border-bottom: .2vh dotted #2d7474;
  144. background-color: #e3e1e1;
  145. color: #323a45;
  146. text-align: center;
  147. padding: 5rem 0 4rem 0;
  148. width: 100%;
  149. font-family: 'ConcourseT3';
  150. display: flex;
  151. flex-direction: column;
  152. }
  153. h1.single {
  154. padding-bottom: 10rem;
  155. }
  156. h1 span {
  157. position: absolute;
  158. top: 1vh;
  159. left: 20%;
  160. line-height: 0;
  161. }
  162. h1 span a {
  163. line-height: 1.7;
  164. padding: 1rem 1.2rem .6rem 1.2rem;
  165. border-radius: 0 0 6% 6%;
  166. background: #2d7474;
  167. font-size: 1.3rem;
  168. color: white;
  169. text-decoration: none;
  170. }
  171. h2 {
  172. margin: 4rem 0 1rem;
  173. border-top: .2vh solid #2d7474;
  174. padding-top: 1vh;
  175. }
  176. h3 {
  177. text-align: center;
  178. margin: 3rem 0 .75em;
  179. }
  180. hr {
  181. height: .4rem;
  182. width: .4rem;
  183. border-radius: .4rem;
  184. background: #07486c;
  185. margin: 2.5rem auto;
  186. }
  187. time {
  188. display: bloc;
  189. margin-left: 0 !important;
  190. }
  191. ul, ol {
  192. margin: 2rem;
  193. }
  194. ul {
  195. list-style-type: square;
  196. }
  197. a {
  198. text-decoration-skip-ink: auto;
  199. text-decoration-thickness: 0.05em;
  200. text-underline-offset: 0.09em;
  201. }
  202. article {
  203. max-width: 50rem;
  204. display: flex;
  205. flex-direction: column;
  206. margin: 2rem auto;
  207. }
  208. article.single {
  209. border-top: .2vh dotted #2d7474;
  210. margin: -6rem auto 1rem auto;
  211. background: #f0f0ea;
  212. padding: 2rem;
  213. }
  214. article p:last-child {
  215. margin-bottom: 1rem;
  216. }
  217. p {
  218. padding: 0 .5rem;
  219. margin-left: 3rem;
  220. }
  221. p + p,
  222. figure + p {
  223. margin-top: 2rem;
  224. }
  225. blockquote {
  226. background-color: #e3e1e1;
  227. border-left: .5vw solid #2d7474;
  228. display: flex;
  229. flex-direction: column;
  230. align-items: center;
  231. padding: 1rem;
  232. margin: 1.5rem;
  233. }
  234. blockquote cite {
  235. font-style: italic;
  236. }
  237. blockquote p {
  238. margin-left: 0;
  239. }
  240. figure {
  241. border-top: .2vh solid #2d7474;
  242. background-color: #e3e1e1;
  243. text-align: center;
  244. padding: 1.5rem 0;
  245. margin: 1rem 0 0;
  246. font-size: 1.5rem;
  247. width: 100%;
  248. }
  249. figure img {
  250. max-width: 250px;
  251. max-height: 250px;
  252. border: .5vw solid #323a45;
  253. padding: 1px;
  254. }
  255. figcaption {
  256. padding: 1rem;
  257. line-height: 1.4;
  258. }
  259. aside {
  260. display: flex;
  261. flex-direction: column;
  262. background-color: #e3e1e1;
  263. padding: 1rem 0;
  264. border-bottom: .2vh solid #07486c;
  265. }
  266. aside p {
  267. max-width: 50rem;
  268. margin: 0 auto;
  269. }
  270. /* https://fvsch.com/code/css-locks/ */
  271. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  272. font-size: 1rem;
  273. line-height: calc( 1.5em + 0.2 * 1rem );
  274. }
  275. h1 {
  276. font-size: 1.9rem;
  277. line-height: calc( 1.2em + 0.2 * 1rem );
  278. }
  279. h2 {
  280. font-size: 1.6rem;
  281. line-height: calc( 1.3em + 0.2 * 1rem );
  282. }
  283. h3 {
  284. font-size: 1.35rem;
  285. line-height: calc( 1.4em + 0.2 * 1rem );
  286. }
  287. @media (min-width: 20em) {
  288. /* The (100vw - 20rem) / (50 - 20) part
  289. resolves to 0-1rem, depending on the
  290. viewport width (between 20em and 50em). */
  291. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  292. font-size: calc( 1rem + .6 * (100vw - 20rem) / (50 - 20) );
  293. line-height: calc( 1.5em + 0.2 * (100vw - 50rem) / (20 - 50) );
  294. margin-left: 0;
  295. }
  296. h1 {
  297. font-size: calc( 1.9rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  298. line-height: calc( 1.2em + 0.2 * (100vw - 50rem) / (20 - 50) );
  299. }
  300. h2 {
  301. font-size: calc( 1.5rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  302. line-height: calc( 1.3em + 0.2 * (100vw - 50rem) / (20 - 50) );
  303. }
  304. h3 {
  305. font-size: calc( 1.35rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  306. line-height: calc( 1.4em + 0.2 * (100vw - 50rem) / (20 - 50) );
  307. }
  308. }
  309. @media (min-width: 50em) {
  310. /* The right part of the addition *must* be a
  311. rem value. In this example we *could* change
  312. the whole declaration to font-size:2.5rem,
  313. but if our baseline value was not expressed
  314. in rem we would have to use calc. */
  315. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  316. font-size: calc( 1rem + .6 * 1rem );
  317. line-height: 1.5em;
  318. }
  319. p, li, pre, details {
  320. margin-left: 3rem;
  321. }
  322. h1 {
  323. font-size: calc( 1.9rem + 1.5 * 1rem );
  324. line-height: 1.2em;
  325. }
  326. h2 {
  327. font-size: calc( 1.5rem + 1.5 * 1rem );
  328. line-height: 1.3em;
  329. }
  330. h3 {
  331. font-size: calc( 1.35rem + 1.5 * 1rem );
  332. line-height: 1.4em;
  333. }
  334. figure img {
  335. max-width: 500px;
  336. max-height: 500px;
  337. }
  338. }
  339. figure.unsquared {
  340. margin-bottom: 1.5rem;
  341. }
  342. figure.unsquared img {
  343. height: inherit;
  344. }
  345. @media print {
  346. body { font-size: 100%; }
  347. a:after { content: " (" attr(href) ")"; }
  348. a, a:link, a:visited, a:after {
  349. text-decoration: underline;
  350. text-shadow: none !important;
  351. background-image: none !important;
  352. background: white;
  353. color: black;
  354. }
  355. abbr[title] { border-bottom: 0; }
  356. abbr[title]:after { content: " (" attr(title) ")"; }
  357. img { page-break-inside: avoid; }
  358. @page { margin: 2cm .5cm; }
  359. h1, h2, h3 { page-break-after: avoid; }
  360. p3 { orphans: 3; widows: 3; }
  361. img {
  362. max-width: 250px !important;
  363. max-height: 250px !important;
  364. }
  365. nav, aside { display: none; }
  366. }
  367. ul.with_columns {
  368. column-count: 1;
  369. }
  370. @media (min-width: 20em) {
  371. ul.with_columns {
  372. column-count: 2;
  373. }
  374. }
  375. @media (min-width: 50em) {
  376. ul.with_columns {
  377. column-count: 3;
  378. }
  379. }
  380. ul.with_two_columns {
  381. column-count: 1;
  382. }
  383. @media (min-width: 20em) {
  384. ul.with_two_columns {
  385. column-count: 1;
  386. }
  387. }
  388. @media (min-width: 50em) {
  389. ul.with_two_columns {
  390. column-count: 2;
  391. }
  392. }
  393. .gallery {
  394. display: flex;
  395. flex-wrap: wrap;
  396. justify-content: space-around;
  397. }
  398. .gallery figure img {
  399. margin-left: 1rem;
  400. margin-right: 1rem;
  401. }
  402. .gallery figure figcaption {
  403. font-family: 'ConcourseT3'
  404. }
  405. footer {
  406. font-family: 'ConcourseT3';
  407. display: flex;
  408. flex-direction: column;
  409. border-top: 3px solid white;
  410. padding: 4rem 0;
  411. background-color: #07486c;
  412. color: white;
  413. }
  414. footer > * {
  415. max-width: 50rem;
  416. margin: 0 auto;
  417. }
  418. footer a {
  419. color: #f1c40f;
  420. }
  421. footer .avatar {
  422. width: 200px;
  423. height: 200px;
  424. border-radius: 50%;
  425. float: left;
  426. -webkit-shape-outside: circle();
  427. shape-outside: circle();
  428. margin-right: 2rem;
  429. padding: 2px 5px 5px 2px;
  430. background: white;
  431. border-left: 1px solid #f1c40f;
  432. border-top: 1px solid #f1c40f;
  433. border-right: 5px solid #f1c40f;
  434. border-bottom: 5px solid #f1c40f;
  435. }
  436. </style>
  437. <h1>
  438. <span><a id="jumper" href="#jumpto" title="Un peu perdu ?">?</a></span>
  439. Real-World JavaScript Anti-Patterns (Part One) (archive)
  440. <time>Pour la pérennité des contenus liés. Non-indexé, retrait sur simple email.</time>
  441. </h1>
  442. <section>
  443. <article>
  444. <h3><a href="http://blog.javascripting.com/2014/11/06/real-world-javascript-anti-patterns/">Source originale du contenu</a></h3>
  445. <p>Code reviews are a perfect opportunity to continue learning and improving your coding style. I work with a team of experienced developers, so I don’t see many really glaring errors. But when I am called on to review third-party code, I’ve noticed certain bad practices crop up over and over again. Some of these may seem obvious, but hopefully there will be a useful tip or two here for JavaScript developers of every skill level. All examples are based on real production code I’ve reviewed, although (variable) names have been changed to protect the innocent.</p>
  446. <p>Consider this gem: </p>
  447. <pre><code class="language-javascript">var otherElements = element.classList.contains('my-class') ?
  448. element.parentNode.parentNode.parentNode.childNodes :
  449. element.parentNode.childNodes;
  450. </code></pre>
  451. <p>The project in question already included jQuery, so one obvious improvement would be to use selectors instead of the execrable DOM API. But that doesn’t address the fundamental issue with this code: it will break if the slightest change is made to the associated markup. The best solution would be to rethink the approach entirely, perhaps using HTML classes to assign semantics to specific elements instead of chaining DOM calls.</p>
  452. <p>Let’s look at some more subtle examples. Even small changes can improve code readability and robustness. This is especially significant when new developers join a project that is already underway. They will get up to speed more quickly and make less mistakes if they don’t need to decipher the existing code base. Clearer code will also prevent them from trying to find hidden meaning where there is none. Consider this event handler:</p>
  453. <pre><code class="language-javascript">MyPage.prototype.resize = function() {
  454. this.renderer.view.style.width = window.innerWidth + 'px';
  455. this.renderer.view.style.height =
  456. window.innerWidth * 0.48828125 + 'px';
  457. };
  458. </code></pre>
  459. <p>Do we need to be so precise? Probably the developer just copied and pasted a constant from their calculator. The less significant digits are completely useless and serve only to obfuscate the intent of the code. Just writing <code>0.49</code> would be an improvement but still doesn’t make it clear what is going on. It would be much better to assign the number to a constant while making it clear how it was derived: </p>
  460. <pre><code class="language-javascript">const SCALING_FACTOR = 500/1024;
  461. ...
  462. MyPage.prototype.resize() = function() {
  463. ...
  464. this.renderer.view.style.height =
  465. window.innerWidth * SCALING_FACTOR + 'px';
  466. }
  467. </code></pre>
  468. <p>Another example is an event handler attached to a button: </p>
  469. <pre><code class="language-javascript">MyButton.prototype.new = function(e) {
  470. var myTarget = e.target;
  471. ...
  472. };
  473. </code></pre>
  474. <p>That’s right, a function declared on a prototype can be named using a reserved word. Surprisingly this works, but to say it’s confusing would be an understatement. Clear and careful naming is as important as code structure itself.</p>
  475. <p>Many anti-patterns relate to basic collections and operations. A classic example: </p>
  476. <pre><code class="language-javascript">items.forEach(function(item) {
  477. doSomething(item);
  478. });
  479. </code></pre>
  480. <p>Similar constructs can be seen for promises, click handlers and anywhere where you unthinkingly type the <code>function</code> keyword. Keep it simple: </p>
  481. <pre><code class="language-javascript">items.forEach(doSomething);
  482. </code></pre>
  483. <p>The situation is more complicated if you need to invoke an object’s method with the right context. Code like this is very common: </p>
  484. <pre><code class="language-javascript">var _this = this;
  485. items.forEach(function(item) {
  486. _this.doSomething(item);
  487. });
  488. </code></pre>
  489. <p>Developers tend to forget about the <code>thisArg</code> parameter of <code>forEach</code> and similar functions, which leads to cleaner, clearer code: </p>
  490. <pre><code class="language-javascript">items.forEach(function(item) {
  491. this.doSomething(item);
  492. }, this);
  493. </code></pre>
  494. <p>And once again, if we are calling a single function, we can change it to a one-liner: </p>
  495. <pre><code class="language-javascript">items.forEach(this.doSomething, this);
  496. </code></pre>
  497. <p>But what about functions that don’t take a <code>thisArg</code> parameter? Imagine you want to avoid the clumsy <code>_this</code> variable when access an object property inside a jQuery click handler. Assigning to <code>_this</code> is unnecessary, thanks to the underused <code>Function.prototype.bind()</code> method: </p>
  498. <pre><code class="language-javascript">el.click(function(e) {
  499. this.clickCount++;
  500. }.bind(this));
  501. </code></pre>
  502. <p>This isn’t the only practical use of the <code>bind</code> function. Less used but no less useful is the ability to create partials with fixed argument values. Remember the dreaded lint error “Don’t make functions within a loop”? Imagine you have an array of DOM elements: </p>
  503. <pre><code class="language-javascript">var i, elems = document.getElementsByClassName("myClass");
  504. </code></pre>
  505. <p>…and the following (wrong) code:</p>
  506. <pre><code class="language-javascript">for (i = 0; i &lt; elems.length; i++) {
  507. elems[i].addEventListener("click", function() {
  508. this.innerHTML = i;
  509. });
  510. }
  511. </code></pre>
  512. <p>The traditional solution is to define a factory function to create the click handler. </p>
  513. <pre><code class="language-javascript">function makeClickHandler(i) {
  514. return function() {
  515. this.innerHTML = i;
  516. };
  517. }
  518. for (i = 0; i &lt; elems.length; i++) {
  519. elems[i].addEventListener("click", makeClickHandler(i));
  520. }
  521. </code></pre>
  522. <p>But <code>Function.prototype.bind()</code> is essentially a factory built into the language itself: </p>
  523. <pre><code class="language-javascript">function handleClick(i) {
  524. this.innerHTML = i;
  525. }
  526. for (i = 0; i &lt; elems.length; i++) {
  527. elems[i].addEventListener("click", handleClick.bind(this, i));
  528. }
  529. </code></pre>
  530. <p>Back to <code>forEach</code>. It is such common construct that is sometimes over- (and mis-)used: </p>
  531. <pre><code class="language-javascript">var left = 0, right = 1;
  532. [left, right].forEach(function(i) {
  533. ...
  534. }, this);
  535. </code></pre>
  536. <p>Here an old-fashioned <code>for</code> loop would be a better choice. You might protest that the author’s choice of variables names is intended to make the code’s semantics more apparent. In this case you can use a code comment or choose a more appropriate data representation. Which representation depends on the specific code, but something like the following is clearly superior to the previous example (note the use of the more powerful Lo-Dash/Underscore <code>forEach</code>): </p>
  537. <pre><code class="language-javascript">data = {left: ..., right: ...};
  538. _.forEach(data, function(item, key) {
  539. ...
  540. });
  541. </code></pre>
  542. <p>Another classic example of <code>forEach</code> abuse: </p>
  543. <pre><code class="language-javascript">var items = [];
  544. data.forEach(function(dataItem) {
  545. var item = dataItem * 4;
  546. items.push(item);
  547. });
  548. </code></pre>
  549. <p>In this simple example it is easy to see that <code>map</code> would be a better choice: </p>
  550. <pre><code class="language-javascript">var items = data.map(function(dataItem) {
  551. return dataItem * 4;
  552. });
  553. </code></pre>
  554. <p>In more complex cases the correct array method can less obvious: </p>
  555. <pre><code class="language-javascript">var lowCounter = 0;
  556. var items = data.map(function(dataItem) {
  557. if (dataItem &lt; 10) lowCounter++;
  558. return dataItem * 5;
  559. });
  560. </code></pre>
  561. <p>Is it appropriate to use <code>map</code> here, considering that the loop has an unrelated side effect? Unless the array is large enough for performance to be a consideration, it would probably be better to use two separate calls, one for the <code>map</code> and one for the side effect: </p>
  562. <pre><code class="language-javascript">var items = data.map(function(dataItem) { return dataItem*5; });
  563. var lowCounter = data.reduce(function(total, current) {
  564. return total + (current &lt; 10);
  565. }, 0);
  566. </code></pre>
  567. <p>One final example: imagine you are using Lo-Dash/Underscore and want merge an array of objects into a single new object. </p>
  568. <pre><code class="language-javascript">var confs = [{a: 1, b: 14}, {foo: 6}, ... ]
  569. </code></pre>
  570. <p>A naive approach might use <code>forEach</code> and <code>_.merge</code>: </p>
  571. <pre><code class="language-javascript">var result = {};
  572. confs.forEach(function(item) {
  573. _.merge(result, item)
  574. });
  575. </code></pre>
  576. <p>A shorter functional approach: </p>
  577. <pre><code class="language-javascript">var result = {} confs.forEach(_.partial(_.merge, result));
  578. </code></pre>
  579. <p>A similar approach using <code>apply</code> (don’t try this with a long array though since each item will be passed to <code>merge</code> as a parameter) </p>
  580. <pre><code class="language-javascript">var result = _.partial(_.merge, {}).apply(this, confs);
  581. </code></pre>
  582. <p>Best of all, of course, is <code>reduce</code>: </p>
  583. <pre><code class="language-javascript">var result = confs.reduce(_.merge, {});
  584. </code></pre>
  585. <p>Use of <code>_.partial</code> makes the code shorter but arguably harder to read. Less code isn’t always better when the result is less understandable. Fortunately we don’t need to weigh the trade-offs in this case since the final variant using <code>reduce</code> is clearly superior.</p>
  586. </article>
  587. </section>
  588. <nav id="jumpto">
  589. <p>
  590. <a href="/david/blog/">Accueil du blog</a> |
  591. <a href="http://blog.javascripting.com/2014/11/06/real-world-javascript-anti-patterns/">Source originale</a> |
  592. <a href="/david/stream/2019/">Accueil du flux</a>
  593. </p>
  594. </nav>
  595. <footer>
  596. <div>
  597. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  598. <p>
  599. Bonjour/Hi!
  600. Je suis <a href="/david/" title="Profil public">David&nbsp;Larlet</a>, je vis actuellement à Montréal et j’alimente cet espace depuis 15 ans. <br>
  601. Si tu as apprécié cette lecture, n’hésite pas à poursuivre ton exploration. Par exemple via les <a href="/david/blog/" title="Expériences bienveillantes">réflexions bimestrielles</a>, la <a href="/david/stream/2019/" title="Pensées (dés)articulées">veille hebdomadaire</a> ou en t’abonnant au <a href="/david/log/" title="S’abonner aux publications via RSS">flux RSS</a> (<a href="/david/blog/2019/flux-rss/" title="Tiens c’est quoi un flux RSS ?">so 2005</a>).
  602. </p>
  603. <p>
  604. Je m’intéresse à la place que je peux avoir dans ce monde. En tant qu’humain, en tant que membre d’une famille et en tant qu’associé d’une coopérative. De temps en temps, je fais aussi des <a href="https://github.com/davidbgk" title="Principalement sur Github mais aussi ailleurs">trucs techniques</a>. Et encore plus rarement, <a href="/david/talks/" title="En ce moment je laisse plutôt la place aux autres">j’en parle</a>.
  605. </p>
  606. <p>
  607. Voici quelques articles choisis :
  608. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  609. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  610. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  611. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  612. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  613. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  614. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  615. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  616. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  617. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  618. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  619. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  620. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  621. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  622. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  623. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  624. </p>
  625. <p>
  626. On peut <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">échanger par courriel</a>. Si éventuellement tu souhaites que l’on travaille ensemble, tu devrais commencer par consulter le <a href="http://larlet.com">profil dédié à mon activité professionnelle</a> et/ou contacter directement <a href="http://scopyleft.fr/">scopyleft</a>, la <abbr title="Société coopérative et participative">SCOP</abbr> dont je fais partie depuis six ans. Je recommande au préalable de lire <a href="/david/blog/2018/cout-site/" title="Attention ce qui va suivre peut vous choquer">combien coûte un site</a> et pourquoi je suis plutôt favorable à une <a href="/david/pro/devis/" title="Discutons-en !">non-demande de devis</a>.
  627. </p>
  628. <p>
  629. Je ne traque pas ta navigation mais mon
  630. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  631. conserve des logs d’accès.
  632. </p>
  633. </div>
  634. </footer>
  635. <script type="text/javascript">
  636. ;(_ => {
  637. const jumper = document.getElementById('jumper')
  638. jumper.addEventListener('click', e => {
  639. e.preventDefault()
  640. const anchor = e.target.getAttribute('href')
  641. const targetEl = document.getElementById(anchor.substring(1))
  642. targetEl.scrollIntoView({behavior: 'smooth'})
  643. })
  644. })()
  645. </script>