{
    "componentChunkName": "component---src-templates-post-js",
    "path": "/blog/2014/02/06/stop-writing-for-loops-start-using-underscorejs",
    "result": {"data":{"site":{"siteMetadata":{"title":"your friend Joel's digital garden","description":"Articles and notes from a collaborator at egghead.io. Musings on software, business, and life from a skilled virtual assistant.","author":{"name":"Joel Hooks"},"keywords":["Video Blogger"]}},"mdx":{"excerpt":"How many for loops did you write today? This week? Sure. That's harmless enough. Ugly and weird, but not something to really complain about. But this is all too common: Which on the scale of bad code, isn't even  that  bad, but you start…","fields":{"github":"https://github.com/joelhooks/joelhooks-com/tree/master/content/legacy_blog/2014-02-06-stop-writing-for-loops-start-using-underscorejs.markdown"},"body":"var _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"layout\": \"post\",\n  \"title\": \"Stop writing For loops. Start using underscore.\",\n  \"date\": \"2014-02-06T00:00:00.000Z\"\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"How many for loops did you write today? This week?\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-javascript\"\n  }, \"var i;\\n\\nfor (i = 0; i < someArray.length; i++) {\\n  var someThing = someArray[i];\\n  doSomeWorkOn(someThing);\\n}\\n\")), mdx(\"p\", null, \"Sure. That's harmless enough. Ugly and weird, but not something to really complain about. But this is all too common:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-javascript\"\n  }, \"var i, j;\\n\\nfor (i = 0; i < someArray.length; i++) {\\n  var someThing = someArray[i];\\n  for (j = 0; j < someThing.stuff.length; j++) {\\n    doSomeWorkOn(someThing.stuff[j]);\\n  }\\n}\\n\")), mdx(\"p\", null, \"Which on the scale of bad code, isn't even \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"that\"), \" bad, but you start throwing some \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"if\"), \"s in there and the insanity really starts.\"), mdx(\"h2\", null, \"I haven't written a For loop in two years.\"), mdx(\"p\", null, \"\\\"The hell you say?\\\"\"), mdx(\"p\", null, \"It's true. Cold turkey. Not a single one (ok, you caught me, I just wrote a couple above), and my code is easier to understand because of my abstinence.\"), mdx(\"p\", null, \"How'd I do it?\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-javascript\"\n  }, \"_.each(someArray, function(someThing) {\\n  doSomeWorkOn(someThing);\\n});\\n\")), mdx(\"p\", null, \"Or, even better:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-javascript\"\n  }, \"_.each(someArray, doSomeWorkOn); //thanks paulmcpazzi!\\n\")), mdx(\"p\", null, \"That's \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://underscorejs.org/\"\n  }, \"underscorejs\"), \" in action. Clean, easy to read, short, no variables, stacks of semi-colons... just plain nice.\"), mdx(\"p\", null, \"Here's another example:\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-javascript\"\n  }, \"var i,\\n  result = [];\\n\\nfor (i = 0; i < someArray.length; i++) {\\n  var someThing = someArray[i];\\n  // my hand already hurts from all this damn typing\\n  if (someThing.isAwesome === true) {\\n    result.push(someArray[i]);\\n  }\\n}\\n\")), mdx(\"p\", null, \"Again, a typical use case for the time honored \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"for\"), \" loop. Meh. Like an ex-smoker or a recently converted vegan, even the sight of the thing fills me with righteous indignation.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-javascript\"\n  }, \"var result = _.filter(someArray, function(someThing) {\\n  return someThing.isAwesome === true;\\n});\\n\")), mdx(\"p\", null, \"As the underscore method name \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"filter\"), \" suggests, this handy 3 lines of easy to parse code gives me a new array of \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"awesome things\"), \".\"), mdx(\"p\", null, \"Or maybe I'd like to do some work on the things and get a new array of the results?\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-javascript\"\n  }, \"var result = _.map(someArray, function(someThing) {\\n  return trasformTheThing(someThing);\\n});\\n\")), mdx(\"p\", null, \"Those three functions are insanely useful on a daily basis, and don't even scratch the surface of what underscore brings to the table.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-javascript\"\n  }, \"var grandTotal = 0,\\n  somePercentage = 1.07,\\n  severalNumbers = [33, 54, 42],\\n  i; // don't forget to hoist those indices;\\n\\nfor (i = 0; i < severalNumbers.length; i++) {\\n  var aNumber = severalNumbers[i];\\n  grandTotal += aNumber * somePercentage;\\n}\\n\")), mdx(\"p\", null, \"Oy.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-javascript\"\n  }, \"var somePercentage = 1.07,\\n  severalNumbers = [33, 54, 42],\\n  grandTotal;\\n\\ngrandTotal = _.reduce(\\n  severalNumbers,\\n  function(runningTotal, aNumber) {\\n    return runningTotal + aNumber * somePercentage;\\n  },\\n  0,\\n);\\n\")), mdx(\"p\", null, \"It seems a little weird at first, and I \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"still\"), \" hit the docs for methods like \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"reduce\"), \" above. Knowing they exist, and a flat refusal to use for loops is my primary weapon. The above methods are really just scratching the surface. The underscorejs library is filled with awesome utilities like this that can be combined together to create new and wonderful things.\"), mdx(\"h2\", null, \"The 30 day no-loop challenge\"), mdx(\"p\", null, \"Stop.\"), mdx(\"p\", null, \"For the next 30 days, don't write any for loops. If you see a nasty pile of those gnarly things, replace them with an \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"each\"), \" or a \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"map\"), \". Do a little \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"reducing\"), \". And let me know how it goes!\"), mdx(\"p\", null, \"Beware. Underscore is the gateway to functional programming. What has been seen, can't be unseen. In a good way!\"), mdx(\"p\", null, \"If you're wanting to dig a little deeper, you should jump over to this tutorial on \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"http://reactivex.io/learnrx/\"\n  }, \"functional programming in javascript\"), \". It's great and only takes about 1/2 hour to work through. It is \\\"how the sausage is made\\\" fundamentals for the underscore functions I used above. Lot's of wholesome nerd fun!\"), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"note\"), \": \", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"As a more performant alternative to underscore, you might check out \", mdx(\"a\", {\n    parentName: \"em\",\n    \"href\": \"https://lodash.com/benchmarks\"\n  }, \"lodash\"))), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"note\"), \": \", mdx(\"em\", {\n    parentName: \"p\"\n  }, \"it should also be noted that modern browsers support the above methods natively. \", mdx(\"inlineCode\", {\n    parentName: \"em\"\n  }, \"Array.forEach\"), \", \", mdx(\"inlineCode\", {\n    parentName: \"em\"\n  }, \"Array.reduce\"), \", and \", mdx(\"inlineCode\", {\n    parentName: \"em\"\n  }, \"Array.map\"), \" exist, but to use them you likely need to create shims to fallback for cases when they don't exist. For me, having the consistent underscore (lodash) API is much more convenient. YMMV\")), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"note\"), \": Yes, for loops \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"are\"), \" faster. I optimize for readability and ease of use for my team before squeezing performance out of CPUs. I don't write games, or rich animated consumer experiences. Big projects, 10s of developers, code that already trends towards sprawling and messy.\"), mdx(\"p\", null, \"The \\\"clean readable code\\\" optimization pays huge dividends, even if it comes at the cost of (very) marginal performance hits.\"), mdx(\"p\", null, \"Now, if we are doing a big list of items in Angular, we focus on performance in terms of CPU, but even then, the only time we hit a wall with an unoptimized datagrid was on last-gen Android phones.\"), mdx(\"p\", null, \"Clean first! ;)\"));\n}\n;\nMDXContent.isMDXComponent = true;","frontmatter":{"title":"Stop writing For loops. Start using underscore.","date":"February 06, 2014","banner":null,"slug":null,"keywords":null}}},"pageContext":{"id":"3ddd2e99-9978-5cc3-ac49-048d61a25b81","prev":{"id":"3d119165-4c79-55dd-8cc5-85429ef2bd4c","parent":{"name":"2014-02-11-lets-make-full-ass-angularjs-directives","sourceInstanceName":"legacy"},"excerpt":"With best intentions we set forth to create the mighty directive. The steepest slope of the dreaded AngularJS learning curve. The \"place where the jQuery goes.\" So what is a directive? We've  talked about this before , and decided that they are  not…","fields":{"title":"Let's Make Full-Ass AngularJS Directives","slug":"blog/2014/02/11/lets-make-full-ass-angularjs-directives","date":"2014-02-11T00:00:00.000Z"}},"next":{"id":"82355fc4-1862-5124-ab63-39418a65f632","parent":{"name":"2013-10-30-how-to-build-a-subscription-service-on-rails-a-noobs-guide","sourceInstanceName":"legacy"},"excerpt":"There are few things as nerve-wracking as pushing your first subscription\nwebsite into production. Am I covering all the bases? Will everything break and\nleave me in a pit of customer support sadness? How do I even take payments? Are\nthey just going…","fields":{"title":"How to Build a Subscription Service on Rails: A Noob's Guide","slug":"blog/2013/10/30/how-to-build-a-subscription-service-on-rails-a-noobs-guide","date":"2013-10-30T00:00:00.000Z"}}}},
    "staticQueryHashes": ["1045846374"]}