[
  {
    "path": ".github/workflows/master.yml",
    "content": "name: Master\n\non:\n  push:\n    branches: [ \"master\" ]\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n# Sets the GITHUB_TOKEN permissions to allow deployment to GitHub Pages\npermissions:\n  contents: write\n  pages: write\n  id-token: write\n\njobs:\n  test:\n    name: Test\n    runs-on: ubuntu-latest\n    environment: testing\n    steps:\n      - name: 👌🏻 Checkout\n        uses: actions/checkout@v3\n      - name: Install dependencies\n        run: npm ci\n      - name: 🔎 Run tests\n        run: npm run test\n      - name: Run unit tests\n        run: npm run test:unit\n"
  },
  {
    "path": ".github/workflows/pr.yml",
    "content": "name: PR\n\non:\n  pull_request:\n    types:\n      - opened\n      - edited\n      - synchronize\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n# Sets the GITHUB_TOKEN permissions to allow deployment to GitHub Pages\npermissions:\n  contents: write\n  pages: write\n  id-token: write\n  pull-requests: write\n\njobs:\n  test:\n    name: Test\n    runs-on: ubuntu-latest\n    environment: testing\n    steps:\n      - name: 👌🏻 Checkout\n        uses: actions/checkout@v3\n      - name: Install Dependencies\n        run: npm ci\n      - name: 🔎 Run tests\n        run: npm run test\n      - name: Run unit tests\n        run: npm run test:unit\n\n  set-automerge:\n    name: Approve and automerge (only dependanbot PRs)\n    runs-on: ubuntu-latest\n    environment: testing\n    needs: [test]\n    if: ${{ github.actor == 'dependabot[bot]' }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v3\n      - name: Dependabot metadata\n        id: dependabot-metadata\n        uses: dependabot/fetch-metadata@v1\n        with:\n          github-token: \"${{ secrets.GITHUB_TOKEN }}\"\n      - name: Approve a PR\n        run: gh pr review --approve \"$PR_URL\"\n        env:\n          PR_URL: ${{github.event.pull_request.html_url}}\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      - name: Enable auto-merge for Dependabot PRs\n        if: ${{ steps.dependabot-metadata.outputs.update-type != 'version-update:semver-major' }}\n        run: gh pr merge --auto --squash \"$PR_URL\"\n        env:\n          PR_URL: ${{ github.event.pull_request.html_url }}\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\ncoverage\nnpm-debug.log\n/.vscode\nyarn.lock"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\r\n\r\nnode_js:\r\n  - 10\r\n  - 12\r\n  - 14\r\n\r\nscript:\r\n  - yarn test\r\n  - yarn test:unit\r\n\r\nafter_success:\r\n  - yarn coveralls\r\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 You-Dont-Need\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# [You don't (may not) need Lodash/Underscore](https://you-dont-need.github.io/You-Dont-Need-Lodash-Underscore/#/)\n\n[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/you-dont-need/lodash-underscore)\n[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cht8687/You-Dont-Need-Lodash-Underscore)\n\nLodash and Underscore are great modern JavaScript utility libraries, and they are widely used by Front-end developers. However, when you are targeting modern browsers, you may find out that there are many methods which are already supported natively thanks to ECMAScript5 [ES5] and ECMAScript2015 [ES6]. If you want your project to require fewer dependencies, and you know your target browser clearly, then you may not need Lodash/Underscore.\n\nYou are welcome to contribute with more items provided below.\n\n* If you are targeting legacy JavaScript engine with those ES5 methods, you can use [es5-shim](https://github.com/es-shims/es5-shim)\n\n* Please note that, the examples used below are just showing you the native alternative of performing certain tasks. For some functions, Lodash provides you more options than native built-ins. This list is not a 1:1 comparison.\n\n* Please send a PR if you want to add or modify the code. No need to open an issue unless it's something big and you want to discuss.\n\n\n## Voice of Developers\n\n> [Make use of native JavaScript object and array utilities before going big.](https://twitter.com/codylindley/status/692356631007342593)\n\n> &mdash;<cite>Cody Lindley, Author of [jQuery Cookbook](http://shop.oreilly.com/product/9780596159788.do) and [JavaScript Enlightenment](http://shop.oreilly.com/product/0636920027713.do)</cite>\n\n<!-- -->\n> [You probably don't need Lodash. Nice List of JavaScript methods which you can use natively.](https://twitter.com/daniellmb/status/692200768556916740)\n\n> &mdash;<cite>Daniel Lamb, Computer Scientist, Technical Reviewer of [Secrets of the JavaScript Ninja](https://www.manning.com/books/secrets-of-the-javascript-ninja-second-edition) and [Functional Programming in JavaScript](https://www.manning.com/books/functional-programming-in-javascript)</cite>\n\n<!-- -->\n> [I guess not, but I want it.](https://twitter.com/teropa/status/692280179666898944)\n\n> &mdash;<cite>Tero Parviainen, Author of [build-your-own-angular](http://teropa.info/build-your-own-angular)</cite>\n\n<!-- -->\n> [I'll admit, I've been guilty of overusing #lodash. Excellent resource.](https://twitter.com/therebelrobot/status/692907269512642561)\n\n> &mdash;<cite>@therebelrobot, Maker of web things, Facilitator for Node.js/io.js</cite>\n\n\n## ESLint Plugin\n\n<div align=\"center\">\n\n[![NPM Version](https://img.shields.io/npm/v/eslint-plugin-you-dont-need-lodash-underscore.svg?style=flat-square)](https://www.npmjs.com/package/eslint-plugin-you-dont-need-lodash-underscore)\n[![Downloads](http://img.shields.io/npm/dm/eslint-plugin-you-dont-need-lodash-underscore.svg?style=flat-square)](https://www.npmjs.org/package/eslint-plugin-you-dont-need-lodash-underscore)\n[![Build Status](https://img.shields.io/travis/you-dont-need/You-Dont-Need-Lodash-Underscore/master.svg?style=flat-square)](https://travis-ci.org/you-dont-need/You-Dont-Need-Lodash-Underscore)\n[![Coverage Status](https://img.shields.io/coveralls/you-dont-need/You-Dont-Need-Lodash-Underscore/master.svg?style=flat-square)](https://coveralls.io/github/you-dont-need/You-Dont-Need-Lodash-Underscore?branch=master)\n\n</div>\n\nIf you're using [ESLint](http://eslint.org/), you can install a\n[plugin](http://eslint.org/docs/user-guide/configuring#using-the-configuration-from-a-plugin) that\nwill help you identify places in your codebase where you don't (may not) need Lodash/Underscore.\n\nInstall the plugin ...\n\n```sh\nnpm install --save-dev eslint-plugin-you-dont-need-lodash-underscore\n```\n\n... then update your config\n\n```json\n\"extends\" : [\"plugin:you-dont-need-lodash-underscore/compatible\"],\n```\n\nFor more information, see [Configuring the ESLint Plugin](configuring.md)\n\n> [!IMPORTANT]\n> Note that, while many Lodash methods are null safe (e.g. _.keys, _.entries),\n> this is not necessarily the case for their Native equivalent. If null safety is critical for your application, we\n> suggest that you take extra precautions [e.g. consider using the native `Object.keys` as `Object.keys(value || {})`].\n\n## Quick Links\n\n**[Array](#array)**\n\n1. [_.chunk](#_chunk)\n1. [_.compact](#_compact)\n1. [_.concat](#_concat)\n1. [_.difference](#_difference)\n1. [_.drop](#_drop)\n1. [_.dropRight](#_dropRight)\n1. [_.fill](#_fill)\n1. [_.find](#_find)\n1. [_.findIndex](#_findindex)\n1. [_.first](#_first)\n1. [_.flatten](#_flatten)\n1. [_.flattenDeep](#_flattendeep)\n1. [_.fromPairs](#_frompairs)\n1. [_.head and _.tail](#_head-and-_tail)\n1. [_.indexOf](#_indexof)\n1. [_.intersection](#_intersection)\n1. [_.isArray](#_isarray)\n1. [_.isArrayBuffer](#_isarraybuffer)\n1. [_.join](#_join)\n1. [_.last](#_last)\n1. [_.lastIndexOf](#_lastindexof)\n1. [_.reverse](#_reverse)\n1. [_.slice](#_slice)\n1. [_.without](#_without)\n1. [_.initial](#_initial)\n1. [_.pull](#_pull)\n1. [_.unionBy](#_unionBy)\n\n**[Collection*](#collection)**\n\n> [!IMPORTANT]\n> Note that most native equivalents are array methods,\n> and will not work with objects. If this functionality is needed and no object method is provided,\n> then Lodash/Underscore might be the better option. Bear in mind however, that all iterable\n> objects can easily be converted to an array by use of the\n> [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax).\n\n1. [_.each](#_each)\n1. [_.every](#_every)\n1. [_.filter](#_filter)\n1. [_.groupBy](#_groupby)\n1. [_.includes](#_includes)\n1. [_.keyBy](#_keyBy)\n1. [_.map](#_map)\n1. [_.minBy and _.maxBy](#_minby-and-_maxby)\n1. [_.orderBy](#_sortby-and-_orderby)\n1. [_.pluck](#_pluck)\n1. [_.range](#_range)\n1. [_.reduce](#_reduce)\n1. [_.reduceRight](#_reduceright)\n1. [_.reject](#_reject)\n1. [_.size](#_size)\n1. [_.some](#_some)\n1. [_.sortBy](#_sortby-and-_orderby)\n1. [_.uniq](#_uniq)\n1. [_.uniqWith](#_uniqWith)\n\n**[Function](#function)**\n\n1. [_.after](#_after)\n1. [_.bind](#_bind)\n1. [_.debounce](#_debounce)\n1. [_.isFunction](#_isFunction)\n1. [_.partial](#_partial)\n1. [_.throttle](#_throttle)\n\n**[Lang](#lang)**\n\n1. [_.castArray](#_castarray)\n1. [.cloneDeep](#_clonedeep)\n1. [_.gt](#_gt)\n1. [_.gte](#_gte)\n1. [_.isDate](#_isdate)\n1. [_.isEmpty](#_isempty)\n1. [_.isFinite](#_isfinite)\n1. [_.isInteger](#_isInteger)\n1. [_.isNaN](#_isnan)\n1. [_.isNil](#_isnil)\n1. [_.isNull](#_isnull)\n1. [_.isUndefined](#_isundefined)\n\n**[Object](#object)**\n\n1. [_.assign](#_assign)\n1. [_.defaults](#_defaults)\n1. [_.extend](#_extend)\n1. [_.has](#_has)\n1. [_.get](#_get)\n1. [_.invert](#_invert)\n1. [_.isPlainObject](#_isplainobject)\n1. [_.keys](#_keys)\n1. [_.mapKeys](#_mapKeys)\n1. [_.omit](#_omit)\n1. [_.pick](#_pick)\n1. [_.pickBy](#_pickby)\n1. [_.toPairs](#_topairs)\n1. [_.values](#_values)\n\n**[String](#string)**\n\n1. [_.capitalize](#_capitalize)\n1. [_.endsWith](#_endsWith)\n1. [_.isString](#_isString)\n1. [_.lowerFirst](#_lowerFirst)\n1. [_.padStart and _.padEnd](#_padstart-and-_padend)\n1. [_.repeat](#_repeat)\n1. [_.replace](#_replace)\n1. [_.split](#_split)\n1. [_.startsWith](#_startsWith)\n1. [_.template](#_template)\n1. [_.toLower](#_tolower)\n1. [_.toUpper](#_toupper)\n1. [_.trim](#_trim)\n1. [_.upperFirst](#_upperFirst)\n\n**[Util](#util)**\n\n1. [_.times](#_times)\n\n**[Number](#number)**\n\n1. [_.clamp](#_clamp)\n2. [_.inRange](#_inRange)\n3. [_.random](#_random)\n\n## Array\n\n### _.chunk\n\nCreates an array of elements split into groups the length of size.\n```js\n// Underscore/Lodash\n_.chunk(['a', 'b', 'c', 'd'], 2);\n// => [['a', 'b'], ['c', 'd']]\n\n_.chunk(['a', 'b', 'c', 'd'], 3);\n// => [['a', 'b', 'c'], ['d']]\n\n\n// Native\n\nconst chunk = (input, size) => {\n  return input.reduce((arr, item, idx) => {\n    return idx % size === 0\n      ? [...arr, [item]]\n      : [...arr.slice(0, -1), [...arr.slice(-1)[0], item]];\n  }, []);\n};\n\nchunk(['a', 'b', 'c', 'd'], 2);\n// => [['a', 'b'], ['c', 'd']]\n\nchunk(['a', 'b', 'c', 'd'], 3);\n// => [['a', 'b', 'c'], ['d']]\n```\n\n#### Browser Support for Spread in array literals\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n   46.0 ✔  | 12.0 ✔ | 16.0 ✔ |  ✖ |  37.0 ✔ |  8.0 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.compact\n\nCreates an array with all falsy values removed.\n\n  ```js\n  // Underscore/Lodash\n  _.compact([0, 1, false, 2, '', 3]);\n  // output: [1, 2, 3]\n\n  // Native\n  [0, 1, false, 2, '', 3].filter(Boolean)\n  // output: [1, 2, 3]\n  ```\n\n#### Browser Support for `array.prototype.filter`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n   ✔  |  ✔ |  1.5 ✔ |  9.0 ✔ |  ✔ |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.concat\n\nCreates a new array concatenating array with any additional arrays and/or values.\n\n  ```js\n  // Underscore/Lodash\n  var array = [1]\n  var other = _.concat(array, 2, [3], [[4]])\n\n  console.log(other)\n  // output: [1, 2, 3, [4]]\n\n  // Native\n  var array = [1]\n  var other = array.concat(2, [3], [[4]])\n\n  console.log(other)\n  // output: [1, 2, 3, [4]]\n  ```\n\n#### Browser Support for `Array.prototype.concat()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n1.0  ✔  | ✔  |  1.0 ✔ |  5.5 ✔  |  ✔  |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.difference\n\nSimilar to [without](#_without), but returns the values from array that are not present in the other arrays.\n\n  ```js\n  // Underscore/Lodash\n  console.log(_.difference([1, 2, 3, 4, 5], [5, 2, 10]))\n  // output: [1, 3, 4]\n\n  // Native\n  var arrays = [[1, 2, 3, 4, 5], [5, 2, 10]];\n  console.log(arrays.reduce(function(a, b) {\n    return a.filter(function(value) {\n      return !b.includes(value);\n    });\n  }));\n  // output: [1, 3, 4]\n\n  // ES6\n  let arrays = [[1, 2, 3, 4, 5], [5, 2, 10]];\n  console.log(arrays.reduce((a, b) => a.filter(c => !b.includes(c))));\n  // output: [1, 3, 4]\n  ```\n\n#### Browser Support for `Array.prototype.reduce()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n   ✔  |  ✔ | 3.0 ✔ |  9.0 ✔  |  10.5 ✔ |  4.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.drop\n\nCreates a slice of array with n elements dropped from the beginning.\n\n  ```js\n  // Underscore/Lodash\n  _.drop([1, 2, 3]);\n  // => [2, 3]\n\n  _.drop([1, 2, 3], 2);\n  // => [3]\n\n  // Native\n  [1, 2, 3].slice(1);\n  // => [2, 3]\n\n  [1, 2, 3].slice(2);\n  // => [3]\n  ```\n\n#### Browser Support for `Array.prototype.slice()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  1.0 ✔  |  ✔  |  1.0 ✔  |  ✔  |  ✔  | ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.dropRight\n\nCreates a slice of array with n elements dropped at the end.\n\n  ```js\n  // Underscore/Lodash\n  _.dropRight([1, 2, 3]);\n  // => [1, 2]\n\n  _.dropRight([1, 2, 3], 2);\n  // => [1]\n\n  // Native\n  [1, 2, 3].slice(0, -1);\n  // => [1, 2]\n\n  [1, 2, 3].slice(0, -2);\n  // => [1]\n  ```\n\n#### Browser Support for `Array.prototype.slice()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  1.0 ✔  |  ✔  |  1.0 ✔  |  ✔  |  ✔  | ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.fill\n\nFills elements of array with value from start up to, but not including, end.\n\n> [!NOTE]\n> `fill` is a mutable method in both native and Lodash/Underscore.\n\n  ```js\n  // Underscore/Lodash\n  var array = [1, 2, 3]\n\n  _.fill(array, 'a')\n\n  console.log(array)\n  // output: ['a', 'a', 'a']\n\n  _.fill(Array(3), 2)\n  // output: [2, 2, 2]\n\n  _.fill([4, 6, 8, 10], '*', 1, 3)\n  // output: [4, '*', '*', 10]\n\n  // Native\n  var array = [1, 2, 3]\n\n  array.fill('a')\n\n  console.log(array)\n  // output: ['a', 'a', 'a']\n\n  Array(3).fill(2)\n  // output: [2, 2, 2]\n\n  [4, 6, 8, 10].fill('*', 1, 3)\n  // output: [4, '*', '*', 10]\n  ```\n\n#### Browser Support for `Array.prototype.fill()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  45.0 ✔ | ✔  | 31.0 ✔ |  ✖  |  32.0 ✔ |  8 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.find\n\nReturns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.\n\n  ```js\n  // Underscore/Lodash\n  var users = [\n    { 'user': 'barney',  'age': 36, 'active': true },\n    { 'user': 'fred',    'age': 40, 'active': false },\n    { 'user': 'pebbles', 'age': 1,  'active': true }\n  ]\n\n  _.find(users, function (o) { return o.age < 40; })\n  // output: object for 'barney'\n\n  // Native\n  var users = [\n    { 'user': 'barney',  'age': 36, 'active': true },\n    { 'user': 'fred',    'age': 40, 'active': false },\n    { 'user': 'pebbles', 'age': 1,  'active': true }\n  ]\n\n  users.find(function (o) { return o.age < 40; })\n  // output: object for 'barney'\n  ```\n\n#### Browser Support for `Array.prototype.find()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  45.0 ✔ | ✔ | 25.0 ✔ |  ✖  |  32.0 ✔ |  7.1 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.findIndex\n\nReturns the index of the first element in the array that satisfies the provided testing function. Otherwise -1 is returned.\n\n  ```js\n  // Underscore/Lodash\n  var users = [\n    { 'user': 'barney',  'age': 36, 'active': true },\n    { 'user': 'fred',    'age': 40, 'active': false },\n    { 'user': 'pebbles', 'age': 1,  'active': true }\n  ]\n\n  var index = _.findIndex(users, function (o) { return o.age >= 40; })\n  console.log(index)\n  // output: 1\n\n  // Native\n  var users = [\n    { 'user': 'barney',  'age': 36, 'active': true },\n    { 'user': 'fred',    'age': 40, 'active': false },\n    { 'user': 'pebbles', 'age': 1,  'active': true }\n  ]\n\n  var index = users.findIndex(function (o) { return o.age >= 40; })\n  console.log(index)\n  // output: 1\n  ```\n\n#### Browser Support for `Array.prototype.findIndex()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  45.0 ✔ | ✔ | 25.0 ✔ |  ✖  |  32.0 ✔ |  7.1 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.first\n\nReturns the first element of an array. Passing n will return the first n elements of the array.\n\n  ```js\n  // Underscore/Lodash\n  _.first([1, 2, 3, 4, 5]);\n  // => 1\n\n  // Underscore\n  _.first([1, 2, 3, 4, 5], 2);\n  // => [1, 2]\n\n  // Native\n  [1, 2, 3, 4, 5][0];\n  // => 1\n  //or\n  [].concat(1, 2, 3, 4, 5).shift()\n  // => 1\n  //or\n  [].concat([1, 2, 3, 4, 5]).shift()\n  // => 1\n\n  // Native (works even with potentially undefined/null, like _.first)\n  [].concat(undefined).shift()\n  // => undefined\n\n  [1, 2, 3, 4, 5].slice(0, 2);\n  // => [1, 2]\n\n  // Native with ES13\n  [1, 2, 3, 4, 5].at(0)\n  // => 1\n  //or\n  [].at(0)\n  // => undefined\n  ```\n\n#### Browser Support for `Array.prototype.slice()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  1.0 ✔  |  ✔  |  1.0 ✔  |  ✔  |  ✔  | ✔  |\n\n#### Browser Support for `Array.prototype.at()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  92 ✔  |  92 ✔  | 90 ✔  | ✖  | 78 ✔  | 15.4 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.flatten\n\nFlattens array a single level deep.\n\n  ```js\n  // Underscore/Lodash\n  _.flatten([1, [2, [3, [4]], 5]]);\n  // => [1, 2, [3, [4]], 5]\n\n  // Native\n  const flatten = [1, [2, [3, [4]], 5]].reduce( (a, b) => a.concat(b), [])\n  // => [1, 2, [3, [4]], 5]\n\n  const flatten = [].concat(...[1, [2, [3, [4]], 5]])\n  // => [1, 2, [3, [4]], 5]\n\n  // Native(ES2019)\n  const flatten = [1, [2, [3, [4]], 5]].flat()\n  // => [1, 2, [3, [4]], 5]\n\n  const flatten = [1, [2, [3, [4]], 5]].flatMap(number => number)\n  // => [1, 2, [3, [4]], 5]\n  ```\n\n#### Browser Support for `Array.prototype.reduce()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: |  :-: |\n  46.0 ✔ |  ✔ | 3.0 ✔ |  9.0 ✔  |  10.5 ✔ |  4 ✔ |\n\n#### Browser Support for `Array.prototype.flat()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |\n:-: | :-: | :-: | :-: | :-: | :-: |\n69 ✔ | 79 ✔ | 62 ✔ | ✖ | 56 ✔ | 12 ✔ |\n\n#### Browser Support for `Array.prototype.flatMap()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |\n:-: | :-: | :-: | :-: | :-: | :-: |\n69 ✔ | 79 ✔ | 62 ✔ | ✖ | 56 ✔ | 12 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.flattenDeep\n\nRecursively flattens array.\n\n  ```js\n  // Underscore/Lodash\n  _.flattenDeep([1, [2, [3, [4]], 5]]);\n  // => [1, 2, 3, 4, 5]\n\n  // Native\n  const flattenDeep = (arr) => Array.isArray(arr)\n    ? arr.reduce( (a, b) => a.concat(flattenDeep(b)) , [])\n    : [arr]\n\n  flattenDeep([1, [[2], [3, [4]], 5]])\n  // => [1, 2, 3, 4, 5]\n\n  // Native(ES2019)\n  [1, [2, [3, [4]], 5]].flat(Infinity)\n  // => [1, 2, 3, 4, 5]\n\n  const flattenDeep = (arr) => arr.flatMap((subArray, index) => Array.isArray(subArray) ? flattenDeep(subArray) : subArray)\n\n  flattenDeep([1, [[2], [3, [4]], 5]])\n  // => [1, 2, 3, 4, 5]\n  ```\n\n#### Browser Support\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  46.0 ✔ |  ✔ | 16.0 ✔ |  ✖  |  37.0 ✔ |  7.1 ✔ |\n\n\n#### Browser Support for `Array.prototype.flat()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |\n:-: | :-: | :-: | :-: | :-: | :-: |\n69 ✔ | 79 ✔ | 62 ✔ | ✖ | 56 ✔ | 12 ✔ |\n\n\n#### Browser Support for `Array.prototype.flatMap()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |\n:-: | :-: | :-: | :-: | :-: | :-: |\n69 ✔ | 79 ✔ | 62 ✔ | ✖ | 56 ✔ | 12 ✔ |\n\n\n**[⬆ back to top](#quick-links)**\n\n### _.fromPairs\n\nReturns an object composed from key-value pairs.\n\n  ```js\n  // Underscore/Lodash\n  _.fromPairs([['a', 1], ['b', 2]]);\n  // => { 'a': 1, 'b': 2 }\n\n  // Native\n  const fromPairs = function(arr) {\n    return arr.reduce(function(accumulator, value) {\n      accumulator[value[0]] = value[1];\n      return accumulator;\n    }, {})\n  }\n\n  // Compact form\n  const fromPairs = (arr) => arr.reduce((acc, val) => (acc[val[0]] = val[1], acc), {})\n\n  fromPairs([['a', 1], ['b', 2]]);\n  // => { 'a': 1, 'b': 2 }\n\n  // Native(ES2019)\n  Object.fromEntries([['a', 1], ['b', 2]])\n  // => { 'a': 1, 'b': 2 }\n  ```\n\n#### Browser Support for `Array.prototype.reduce()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  |  ✔ | 3.0 ✔ |  9.0 ✔  |  10.5 ✔ |  4.0 ✔ |\n\n#### Browser Support for `Object.fromEntries()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  73.0 ✔  | 79.0 ✔ | 63.0 ✔ |  ✖  |  60 ✔ |  12.1 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.head and _.tail\n\nGets the first element or all but the first element.\n\n  ```js\n  const array = [1, 2, 3]\n\n  // Underscore: _.first, _.head, _.take\n  // Lodash: _.first, _.head\n  _.head(array)\n  // output: 1\n\n  // Underscore: _.rest, _.tail, _.drop\n  // Lodash: _.tail\n  _.tail(array)\n  // output: [2, 3]\n\n\n  // Native\n  const [ head, ...tail ] = array\n  console.log(head)\n  // output: 1\n  console.log(tail)\n  // output [2, 3]\n\n  // Native replacement for _.head in ES13\n  array.at(0)\n  // output: 1\n  ```\n\n#### Browser Support for Spread in array literals\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  46.0 ✔  | 12.0 ✔ |  16.0 ✔ |  ✖ |  37.0 ✔ | 8.0 ✔  |\n\n#### Browser Support for `Array.prototype.at()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  92 ✔  |  92 ✔  | 90 ✔  | ✖  | 78 ✔  | 15.4 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.indexOf\n\nReturns the first index at which a given element can be found in the array, or -1 if it is not present.\n\n  ```js\n  // Underscore/Lodash\n  var array = [2, 9, 9]\n  var result = _.indexOf(array, 2)\n  console.log(result)\n  // output: 0\n\n  // Native\n  var array = [2, 9, 9]\n  var result = array.indexOf(2)\n  console.log(result)\n  // output: 0\n  ```\n\n#### Browser Support for `Array.prototype.indexOf()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔  |  1.5 ✔ |  9.0 ✔  |  ✔  |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.intersection\n\nReturns an array that is the intersection of all the arrays. Each value in the result is present in each of the arrays.\n\n  ```js\n  // Underscore/Lodash\n  console.log(_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]))\n  // output: [1, 2]\n\n  // Native\n  var arrays = [[1, 2, 3], [101, 2, 1, 10], [2, 1]];\n  console.log(arrays.reduce(function(a, b) {\n    return a.filter(function(value) {\n      return b.includes(value);\n    });\n  }));\n  // output: [1, 2]\n\n  // ES6\n  let arrays = [[1, 2, 3], [101, 2, 1, 10], [2, 1]];\n  console.log(arrays.reduce((a, b) => a.filter(c => b.includes(c))));\n  // output: [1, 2]\n  ```\n\n#### Browser Support for `Array.prototype.reduce()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  |  ✔ | 3.0 ✔ |  9.0 ✔  |  10.5 ✔ |  4.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.takeRight\n\nCreates a slice of array with n elements taken from the end.\n\n> [!IMPORTANT]\n> Native slice does not behave entirely the same as the `Lodash` method. See example below to understand why.\n\n  ```js\n  // Underscore/Lodash\n  _.takeRight([1, 2, 3]);\n  // => [3]\n\n  _.takeRight([1, 2, 3], 2);\n  // => [2, 3]\n\n  _.takeRight([1, 2, 3], 5);\n  // => [1, 2, 3]\n\n  // Native\n  [1, 2, 3].slice(-1);\n  // => [3]\n\n  [1, 2, 3].slice(-2);\n  // => [2, 3]\n\n  [1, 2, 3].slice(-5);\n  // => [1, 2, 3]\n\n  // Difference in compatibility\n\n  // Lodash\n  _.takeRight([1, 2, 3], 0);\n  // => []\n\n  // Native\n  [1, 2, 3].slice(0);\n  // => [1, 2, 3]\n  ```\n\n#### Browser Support for `Array.prototype.slice()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  1.0 ✔  |  ✔  |  1.0 ✔  |  ✔  |  ✔  | ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isArray\n\nReturns true if given value is an array.\n\n  ```js\n  // Lodash\n  var array = []\n  console.log(_.isArray(array))\n  // output: true\n\n  // Native\n  var array = []\n  console.log(Array.isArray(array));\n  // output: true\n  ```\n\n#### Browser Support for `Array.isArray()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  5.0 ✔  |  ✔  | 4.0 ✔  |  9.0 ✔  |  10.5 ✔  | 5.0 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isArrayBuffer\n\nChecks if value is classified as an ArrayBuffer object.\n\n  ```js\n  // Lodash\n  _.isArrayBuffer(new ArrayBuffer(2));\n  // output: true\n\n  // Native\n  console.log(new ArrayBuffer(2) instanceof ArrayBuffer);\n  // output: true\n  ```\n\n> [!WARNING]\n> You will get the wrong result if you get `ArrayBuffer` from another realm.\n> [See details](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof#instanceof_and_multiple_context_e.g._frames_or_windows).\n\n#### Browser Support for `instanceof`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  |  ✔  | 1.0 ✔  | ✔  | ✔  | ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.join\n\n> [!IMPORTANT]\n> Not in Underscore.js\n\nJoins a list of elements in an array with a given separator.\n\n  ```js\n  // Lodash\n  var result = _.join(['one', 'two', 'three'], '--')\n  console.log(result)\n  // output: 'one--two--three'\n\n  // Native\n  var result = ['one', 'two', 'three'].join('--')\n  console.log(result)\n  // output: 'one--two--three'\n  ```\n\n#### Browser Support for `Array.prototype.join()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  1.0 ✔  |   ✔  | 1.0 ✔ |  5.5 ✔  |  ✔ |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.last\n\nReturns the last element of an array. Passing n will return the last n elements of the array.\n\n  ```js\n  // Underscore/Lodash\n  const numbers = [1, 2, 3, 4, 5];\n  _.last(numbers);\n  // => 5\n\n  // Underscore\n  _.last(numbers, 2);\n  // => [4, 5]\n\n  // Native\n  const numbers = [1, 2, 3, 4, 5];\n  numbers[numbers.length - 1];\n  // => 5\n  //or\n  numbers.slice(-1)[0];\n  // => 5\n  //or\n  [].concat(numbers).pop()\n  // => 5\n  //or\n  numbers.at(-1);\n  // => 5\n\n  // Native (works even with potentially undefined/null)\n  [].concat(undefined).pop()\n  // => undefined\n\n  numbers.slice(-2);\n  // => [4, 5]\n  ```\n\n#### Browser Support for `Array.prototype.concat()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  1.0 ✔  |  ✔  | 1.0 ✔  | 5.5 ✔  |  ✔  | ✔  |\n\n#### Browser Support for `Array.prototype.at()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  92 ✔  |  92 ✔  | 90 ✔  | ✖  | 78 ✔  | 15.4 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.lastIndexOf\n\nReturns the index of the last occurrence of value in the array, or -1 if value is not present.\n\n  ```js\n  // Underscore/Lodash\n  var array = [2, 9, 9, 4, 3, 6]\n  var result = _.lastIndexOf(array, 9)\n  console.log(result)\n  // output: 2\n\n  // Native\n  var array = [2, 9, 9, 4, 3, 6]\n  var result = array.lastIndexOf(9)\n  console.log(result)\n  // output: 2\n  ```\n\n#### Browser Support for `Array.prototype.lastIndexOf()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  |  ✔ | 1.5 ✔  | 9.0 ✔  |  ✔  |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.reverse\n\n> [!IMPORTANT]\n> Not in Underscore.js\n\nReverses array so that the first element becomes the last, the second element becomes the second to last, and so on.\n\n  ```js\n  // Lodash\n  var array = [1, 2, 3]\n  console.log(_.reverse(array))\n  // output: [3, 2, 1]\n\n  // Native\n  var array = [1, 2, 3]\n  console.log(array.reverse())\n  // output: [3, 2, 1]\n  ```\n\nVoice from the Lodash author:\n\n> Lodash's `_.reverse` just calls `Array#reverse` and enables composition like `_.map(arrays, _.reverse).`\n> It's exposed on _ because previously, like `Underscore`, it was only exposed in the chaining syntax.\n> --- [jdalton](https://github.com/cht8687/You-Dont-Need-Lodash-Underscore/commit/22c4bcf2be48dd415d2b073759805562e520b615#)\n\n#### Browser Support for `Array.prototype.reverse()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 1.5 ✔ |  9 ✔ |  ✔ |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.slice\n\nReturns a shallow copy of a portion of an array into a new array object selected from `begin` to `end` (`end` not included)\n\n  ```js\n  // Lodash\n  var array = [1, 2, 3, 4]\n  console.log(_.slice(array, 1, 3))\n  // output: [2, 3]\n\n  // Native\n  var array = [1, 2, 3, 4]\n  console.log(array.slice(1, 3));\n  // output: [2, 3]\n  ```\n\n#### Browser Support for `Array.prototype.slice()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  1.0 ✔  |  ✔  |  1.0 ✔  |  ✔  |  ✔  |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.without\n\n> [!IMPORTANT]\n> Not in Underscore.js\n\nReturns an array where matching items are filtered.\n\n  ```js\n  // Lodash\n  var array = [1, 2, 3]\n  console.log(_.without(array, 2))\n  // output: [1, 3]\n\n  // Native\n  var array = [1, 2, 3]\n  console.log(array.filter(function(value) {\n    return value !== 2;\n  }));\n  // output: [1, 3]\n  ```\n\n#### Browser Support for `Array.prototype.filter()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  1.0 ✔  | ✔ | 1.5 ✔ |  9 ✔ |  ✔ |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.initial\n\nReturns everything but the last entry of the array. Pass n to exclude the last n elements from the result.\n\n  ```js\n  // Underscore\n  var array = [5, 4, 3, 2, 1]\n  console.log(_.initial(array, 2))\n  // output: [5, 4, 3]\n\n  // Native\n  var array = [5, 4, 3, 2, 1]\n  console.log(array.slice(0, -2));\n  // output: [5, 4, 3]\n  ```\n\n#### Browser Support for `Array.prototype.slice()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  1.0 ✔  |  ✔  |  1.0 ✔  |  ✔  |  ✔  | ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.pull\n\nRemoves all provided values from the given array using strict equality for comparisons, i.e. ===.\n\n  ```js\n  // Lodash\n  const array = [1, 2, 3, 1, 2, 3];\n  _.pull(array, 2, 3);\n  console.log(array); // output: [1, 1]\n  ```\n\n  ```js\n  // Native JS\n  const array = [1, 2, 3, 1, 2, 3];\n  function pull(arr, ...removeList){\n      var removeSet = new Set(removeList)\n      return arr.filter(function(el){\n          return !removeSet.has(el)\n      })\n  }\n  console.log(pull(array, 2, 3)); // output: [1, 1]\n  console.log(array); // still [1, 2, 3, 1, 2, 3]. This is not in place, unlike lodash!\n  ```\n\n  ```ts\n  // TypeScript\n  const array = [1, 2, 3, 1, 2, 3];\n  const pull = <T extends unknown>(sourceArray: T[], ...removeList: T[]): T[] => {\n    const removeSet = new Set(removeList);\n    return sourceArray.filter(el => !removeSet.has(el));\n  };\n  console.log(pull(array, 2, 3)); // output: [1, 1]\n  console.log(array); // still [1, 2, 3, 1, 2, 3]. This is not in place, unlike lodash!\n  ```\n\n#### Browser Support for `Array.prototype.filter()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  1.0 ✔  | ✔ | 1.5 ✔ |  9 ✔ |  ✔ |  ✔  |\n\n#### Browser Support for `Set.prototype.has()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |\n:-: | :-: | :-: | :-: | :-: | :-: |\n38 ✔ | 12 ✔ | 13 ✔ | 11 ✔ | 25 ✔ | 8 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.unionBy\n\nCreates an array of unique values, taking an `iteratee` to compute uniqueness with\n(note that to iterate by a key in an object you must use `x => x.key` instead of `key` for the `iteratee`)\n\n  ```js\n  // Lodash\n  var array1 = [2.1];\n  var array2 = [1.2, 2.3];\n  var result = _.unionBy(array1, array2, Math.floor)\n  console.log(result)\n  // output: [2.1, 1.2]\n\n  // Native\n  var array1 = [2.1];\n  var array2 = [1.2, 2.3];\n  function unionBy(...arrays) {\n      const iteratee = (arrays).pop();\n\n      if (Array.isArray(iteratee)) {\n          return []; // return empty if iteratee is missing\n      }\n\n      return [...arrays].flat().filter(\n          (set => (o) => set.has(iteratee(o)) ? false : set.add(iteratee(o)))(new Set()),\n      );\n  };\n  console.log(unionBy(array1, array2, Math.floor))\n  // output: [2.1, 1.2]\n  ```\n\n#### Browser Support for `Array.prototype.flat()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |\n:-: | :-: | :-: | :-: | :-: | :-: |\n69 ✔ | 79 ✔ | 62 ✔ | ✖ | 56 ✔ | 12 ✔ |\n\n#### Browser Support for `Array.isArray()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n5.0 ✔  |  ✔  | 4.0 ✔  |  9.0 ✔  |  10.5 ✔  | 5.0 ✔  |\n\n#### Browser Support for `Set.prototype.has()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] |\n:-: | :-: | :-: | :-: | :-: | :-: |\n38 ✔ | 12 ✔ | 13 ✔ | 11 ✔ | 25 ✔ | 8 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n## Collection*\n\n> [!IMPORTANT]\n> Most native equivalents are array methods,\n> and will not work with objects. If this functionality is needed and no object method is provided,\n> then Lodash/Underscore is the better option.\n\n### _.each\n\nIterates over a list of elements, yielding each in turn to an iteratee function.\n\n  ```js\n  // Underscore/Lodash\n  //For arrays\n  _.each([1, 2, 3], function (value, index) {\n    console.log(value)\n  })\n  // output: 1 2 3\n\n  //For objects\n  _.each({'one':1, 'two':2, 'three':3}, function(value) {\n    console.log(value)\n  })\n  // output: 1 2 3\n\n  // Native\n  //For arrays\n  [1, 2, 3].forEach(function (value, index) {\n    console.log(value)\n  })\n  // output: 1 2 3\n\n  //For objects\n  Object.entries({'one':1, 'two':2, 'three':3}).forEach(function([key,value],index) {\n    console.log(value)\n  })\n  //output: 1 2 3\n  ```\n\n#### Browser Support for `Array.prototype.forEach()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 1.5 ✔ |  9.0 ✔  |  ✔  |  ✔  |\n\n#### Browser Support for `Object.entries().forEach()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  54 ✔  | 14 ✔ | 47 ✔ |  ✖  |  41 ✔  |  10.1✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.every\n\nTests whether all elements in the array pass the test implemented by the provided function.\n\n  ```js\n  // Underscore/Lodash\n  function isLargerThanTen (element, index, array) {\n    return element >= 10\n  }\n  var array = [10, 20, 30]\n  var result = _.every(array, isLargerThanTen)\n  console.log(result)\n  // output: true\n\n  // Native\n  function isLargerThanTen (element, index, array) {\n    return element >= 10\n  }\n\n  var array = [10, 20, 30]\n  var result = array.every(isLargerThanTen)\n  console.log(result)\n  // output: true\n  ```\n\n#### Browser Support for `Array.prototype.every()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 1.5 ✔ |  9.0 ✔  |  ✔  |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.filter\n\nCreates a new array with all elements that pass the test implemented by the provided function.\n\n  ```js\n  // Underscore/Lodash\n  function isBigEnough (value) {\n    return value >= 10\n  }\n  var array = [12, 5, 8, 130, 44]\n  var filtered = _.filter(array, isBigEnough)\n  console.log(filtered)\n  // output: [12, 130, 44]\n\n  // Native\n  function isBigEnough (value) {\n    return value >= 10\n  }\n  var array = [12, 5, 8, 130, 44]\n  var filtered = array.filter(isBigEnough)\n  console.log(filtered)\n  // output: [12, 130, 44]\n  ```\n\n#### Browser Support for `Array.prototype.filter()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 1.5 ✔ |  9 ✔  |  ✔  |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.groupBy\n\nGroup items by key.\n\n  ```js\n  // Underscore/Lodash\n  var grouped = _.groupBy(['one', 'two', 'three'], 'length')\n  console.log(grouped)\n  // output: {3: [\"one\", \"two\"], 5: [\"three\"]}\n\n  // Native\n  var grouped = ['one', 'two', 'three'].reduce((r, v, i, a, k = v.length) => ((r[k] || (r[k] = [])).push(v), r), {})\n  console.log(grouped)\n  // output: {3: [\"one\", \"two\"], 5: [\"three\"]}\n\n  // Native\n  Object.groupBy(['one', 'two', 'three'], ({length}) => length)\n  // output: {3: [\"one\", \"two\"], 5: [\"three\"]}\n  ```\n\n  ```js\n  // Underscore/Lodash\n  var grouped = _.groupBy([1.3, 2.1, 2.4], num => Math.floor(num))\n  console.log(grouped)\n  // output: {1: [1.3], 2: [2.1, 2.4]}\n\n  // Native\n  var grouped = [1.3, 2.1, 2.4].reduce((r, v, i, a, k = Math.floor(v)) => ((r[k] || (r[k] = [])).push(v), r), {})\n  console.log(grouped)\n  // output: {1: [1.3], 2: [2.1, 2.4]}\n\n  // Native\n  Object.groupBy([1.3, 2.1, 2.4], num => Math.floor(num))\n  // output: {1: [1.3], 2: [2.1, 2.4]}\n  ```\n\n#### Browser Support for `Array.prototype.reduce()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔  | 3.0 ✔ |  9.0 ✔  |  10.5 ✔ |  4.0 ✔ |\n\n#### Browser Support for `Object.groupBy()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  117.0 ✔  | 117.0 ✔ | 119.0 ✔ |  ✖  |  103.0 ✔ |  16.4 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.includes\n\nChecks if a value is in collection.\n\n  ```js\n  var array = [1, 2, 3]\n  // Underscore/Lodash - also called _.contains\n  _.includes(array, 1)\n  // output: true\n\n  // Native\n  var array = [1, 2, 3]\n  array.includes(1)\n  // output: true\n\n  // Native (does not use same value zero)\n  var array = [1, 2, 3]\n  array.indexOf(1) > -1\n  // output: true\n  ```\n\n#### Browser Support for `Array.prototype.includes`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  47.0 ✔  | 14.0 ✔ | 43.0 ✔ |  ✖  |  34.0 ✔ |  9.0 ✔ |\n\n#### Browser Support for `Array.prototype.indexOf`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔ | ✔ | 1.5 ✔ | 9.0 ✔ | ✔ | ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.keyBy\n\n> [!WARNING]\n> Not in Underscore.js\n\nCreates an object composed of keys generated from the results of running each element of collection through iteratee.\n\n  ```js\n  // Lodash\n  console.log(_.keyBy(['a', 'b', 'c']))\n  // output: { a: 'a', b: 'b', c: 'c' }\n  console.log(_.keyBy([{ id: 'a1', title: 'abc' }, { id: 'b2', title: 'def' }], 'id'))\n  // output: { a1: { id: 'a1', title: 'abc' }, b2: { id: 'b2', title: 'def' } }\n  console.log(_.keyBy({ data: { id: 'a1', title: 'abc' }}, 'id'))\n  // output: { a1: { id: 'a1', title: 'abc' }}\n\n  // keyBy for array only\n  const keyBy = (array, key) => (array || []).reduce((r, x) => ({ ...r, [key ? x[key] : x]: x }), {});\n\n  // Native\n  console.log(keyBy(['a', 'b', 'c']))\n  // output: { a: 'a', b: 'b', c: 'c' }\n  console.log(keyBy([{ id: 'a1', title: 'abc' }, { id: 'b2', title: 'def' }], 'id'))\n  // output: { a1: { id: 'a1', title: 'abc' }, b2: { id: 'b2', title: 'def' } }\n  console.log(keyBy(Object.values({ data: { id: 'a1', title: 'abc' }}), 'id'))\n  // output: { a1: { id: 'a1', title: 'abc' }}\n\n  // keyBy for array and object\n  const collectionKeyBy = (collection, key) => {\n    const c = collection || {};\n    return c.isArray() ? keyBy(c, key) : keyBy(Object.values(c), key);\n  }\n  ```\n\n#### Browser Support for `Array.prototype.reduce()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | 12.0 ✔ | 3.0 ✔ |  9.0 ✔  |  10.5 ✔ |  4.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.map\n\nTranslates all items in an array or object to new array of items.\n\n  ```js\n  // Underscore/Lodash\n  var array1 = [1, 2, 3]\n  var array2 = _.map(array1, function (value, index) {\n    return value * 2\n  })\n  console.log(array2)\n  // output: [2, 4, 6]\n\n  // Native\n  var array1 = [1, 2, 3]\n  var array2 = array1.map(function (value, index) {\n    return value * 2\n  })\n  console.log(array2)\n  // output: [2, 4, 6]\n  ```\n\n  ```js\n  // Underscore/Lodash\n  var object1 = { 'a': 1, 'b': 2, 'c': 3 }\n  var object2 = _.map(object1, function (value, index) {\n    return value * 2\n  })\n  console.log(object2)\n  // output: [2, 4, 6]\n\n  // Native\n  var object1 = { 'a': 1, 'b': 2, 'c': 3 }\n  var object2 = Object.entries(object1).map(function ([key, value], index) {\n    return value * 2\n  })\n  console.log(object2)\n  // output: [2, 4, 6]\n  ```\n\n#### Browser Support for `Object.entries()` and destructuring\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 1.5 ✔ |  ✖ |  ✔ |  ✔ |\n\n#### Browser Support for `Array.prototype.map()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 1.5 ✔ |  9.0 ✔  |  ✔ |  ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.minBy and _.maxBy\n\nUse `Array.prototype.reduce()` for find the maximum or minimum collection item\n\n  ```js\n  // Underscore/Lodash\n  var data = [{ value: 6 }, { value: 2 }, { value: 4 }]\n  var minItem = _.minBy(data, 'value')\n  var maxItem = _.maxBy(data, 'value')\n  console.log(minItem, maxItem)\n  // output: { value: 2 } { value: 6 }\n\n  // Native\n  var data = [{ value: 6 }, { value: 2 }, { value: 4 }]\n  var minItem = data.reduce(function(a, b) { return a.value <= b.value ? a : b }, {})\n  var maxItem = data.reduce(function(a, b) { return a.value >= b.value ? a : b }, {})\n  console.log(minItem, maxItem)\n  // output: { value: 2 }, { value: 6 }\n  ```\n\nExtract a functor and use es2015 for better code\n\n  ```js\n  // utils\n  const makeSelect = (comparator) => (a, b) => comparator(a, b) ? a : b\n  const minByValue = makeSelect((a, b) => a.value <= b.value)\n  const maxByValue = makeSelect((a, b) => a.value >= b.value)\n\n  // main logic\n  const data = [{ value: 6 }, { value: 2 }, { value: 4 }]\n  const minItem = data.reduce(minByValue, {})\n  const maxItem = data.reduce(maxByValue, {})\n\n  console.log(minItem, maxItem)\n  // output: { value: 2 }, { value: 6 }\n\n  // or also more universal and little slower variant of minBy\n  const minBy = (collection, key) => {\n    // slower because need to create a lambda function for each call...\n    const select = (a, b) => a[key] <= b[key] ? a : b\n    return collection.reduce(select, {})\n  }\n\n  console.log(minBy(data, 'value'))\n  // output: { value: 2 }\n  ```\n\n#### Browser Support for `Array.prototype.reduce()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 3.0 ✔ |  9.0 ✔  |  10.5 ✔ |  4.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.pluck\n\n`array.map` or `_.map` can also be used to replace `_.pluck`.\nLodash v4.0 removed `_.pluck` in favor of `_.map` with iteratee shorthand.\nDetails can be found in [Changelog](https://github.com/lodash/lodash/wiki/Changelog)\n\n  ```js\n  // Underscore/Lodash\n  var array1 = [{name: \"Alice\"}, {name: \"Bob\"}, {name: \"Jeremy\"}]\n  var names = _.pluck(array1, \"name\")\n  console.log(names)\n  // output: [\"Alice\", \"Bob\", \"Jeremy\"]\n\n  // Native\n  var array1 = [{name: \"Alice\"}, {name: \"Bob\"}, {name: \"Jeremy\"}]\n  var names = array1.map(function(x){\n    return x.name\n  })\n  console.log(names)\n  // output: [\"Alice\", \"Bob\", \"Jeremy\"]\n  ```\n\n#### Browser Support for `Array.prototype.map()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  |  ✔ | 1.5 ✔ |  9.0 ✔  |  ✔  |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.reduce\n\nApplies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.\n\n  ```js\n  // Underscore/Lodash\n  var array = [0, 1, 2, 3, 4]\n  var result = _.reduce(array, function (previousValue, currentValue, currentIndex, array) {\n    return previousValue + currentValue\n  })\n  console.log(result)\n  // output: 10\n\n  // Native\n  var array = [0, 1, 2, 3, 4]\n  var result = array.reduce(function (previousValue, currentValue, currentIndex, array) {\n    return previousValue + currentValue\n  })\n  console.log(result)\n  // output: 10\n  ```\n\n#### Browser Support for `Array.prototype.reduce()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] |  ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 3.0 ✔ |  9.0 ✔  |  10.5 ✔ |  4.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.range\n\nCreates an array of numbers progressing from start up to.\n\n  ```js\n  // Underscore/Lodash\n  _.range(4)  // output: [0, 1, 2, 3]\n  _.range(-4) // output: [0, -1, -2, -3]\n  _.range(1, 5)     // output: [1, 2, 3, 4]\n  _.range(0, 20, 5) // output: [0, 5, 10, 15]\n\n  // Native ( solution with Array.from )\n  Array.from({length: 4}, (_, i) => i)  // output: [0, 1, 2, 3]\n  Array.from({length: 4}, (_, i) => -i) // output: [-0, -1, -2, -3]\n  Array.from({length: 4}, (_, i) => i + 1) // output: [1, 2, 3, 4]\n  Array.from({length: 4}, (_, i) => i * 5) // output: [0, 5, 10, 15]\n\n  // Native ( solution with keys() and spread )\n  [...Array(4).keys()]  // output: [0, 1, 2, 3]\n  [...Array(4).keys()].map(k => -k) // output: [-0, -1, -2, -3]\n  [...Array(4).keys()].map(k => k + 1)  // output: [1, 2, 3, 4]\n  [...Array(4).keys()].map(k => k * 5)  // output: [0, 5, 10, 15]\n  ```\n\n\n#### Browser Support for `Array.from()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n 45.0 ✔  |  ✔ |  32.0 ✔ |  ✖   |  ✔ |  9.0 ✔ |\n\n#### Browser Support for keys and spread in Array literals\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n 46.0 ✔  |  12.0 ✔ |  16.0 ✔ |  ✖ | 37.0 ✔ |  7.1 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.reduceRight\n\nThis method is like _.reduce except that it iterates over elements of collection from right to left.\n\n  ```js\n  // Underscore/Lodash\n  var array = [0, 1, 2, 3, 4]\n  var result = _.reduceRight(array, function (previousValue, currentValue, currentIndex, array) {\n    return previousValue - currentValue\n  })\n  console.log(result)\n  // output: -2\n\n  // Native\n  var array = [0, 1, 2, 3, 4]\n  var result = array.reduceRight(function (previousValue, currentValue, currentIndex, array) {\n    return previousValue - currentValue\n  })\n  console.log(result)\n  // output: -2\n  ```\n\n#### Browser Support for `Array.prototype.reduceRight()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 3.0 ✔ |  9.0 ✔  |  10.5 ✔ |  4.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.reject\n\nThe opposite of _.filter; this method returns the elements of collection that predicate does not return truthy for.\n\n  ```js\n  // Underscore/Lodash\n  var array = [1, 2, 3, 4, 5];\n  var result = _.reject(array, function (x) {\n    return x % 2 === 0;\n  });\n  // output: [1, 3, 5]\n\n  // Native\n  var array = [1, 2, 3, 4, 5];\n\n  var reject = function (arr, predicate) {\n    var complement = function (f) {\n      return function (x) {\n        return !f(x);\n      }\n    };\n\n    return arr.filter(complement(predicate));\n  };\n  // output: [1, 3, 5]\n  ```\n\n#### Browser Support for `Array.prototype.filter()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | 12 ✔ | 1.5 ✔ |  9.0 ✔  |  9.5 ✔ |  3.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.sample\n\nGets a random element from `array`.\n\n  ```js\n  // Underscore/Lodash\n  const array = [0, 1, 2, 3, 4]\n  const result = _.sample(array)\n  console.log(result)\n  // output: 2\n\n  // Native\n  const array = [0, 1, 2, 3, 4]\n  const sample = arr => {\n    const len = arr == null ? 0 : arr.length\n    return len ? arr[Math.floor(Math.random() * len)] : undefined\n  }\n\n  const result = sample(array)\n  console.log(result)\n  // output: 2\n  ```\n\n#### Browser Support for `Array.prototype.length()` and `Math.random()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 1.0 ✔ |  ✔  |  ✔ |  ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.size\n\nReturns the number of values in the collection.\n\n  ```js\n  // Underscore/Lodash\n  var result = _.size({one: 1, two: 2, three: 3})\n  console.log(result)\n  // output: 3\n\n  // Native\n  var result2 = Object.keys({one: 1, two: 2, three: 3}).length\n  console.log(result2)\n  // output: 3\n  ```\n\n#### Browser Support for `Object.keys()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  5.0 ✔  | ✔ | 4.0 ✔ |  9.0 ✔ |  12.0 ✔ |  5.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.some\n\nTests whether any of the elements in the array pass the test implemented by the provided function.\n\n  ```js\n  // Underscore/Lodash\n  function isLargerThanTen (element, index, array) {\n    return element >= 10\n  }\n  var array = [10, 9, 8]\n  var result = _.some(array, isLargerThanTen)\n  console.log(result)\n  // output: true\n\n  // Native\n  function isLargerThanTen (element, index, array) {\n    return element >= 10\n  }\n\n  var array = [10, 9, 8]\n  var result = array.some(isLargerThanTen)\n  console.log(result)\n  // output: true\n  ```\n\n#### Browser Support for `Array.prototype.some()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 1.5 ✔ |  ✔ 9.0  |  ✔  | ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.sortBy and _.orderBy\n\nSorts an array of object based on an object key provided by a parameter (note this is more limited than Underscore/Lodash).\n\n  ```js\n  const fruits = [\n    {name:\"banana\", amount: 2},\n    {name:\"apple\", amount: 4},\n    {name:\"pineapple\", amount: 2},\n    {name:\"mango\", amount: 1}\n  ];\n\n  // Underscore\n  _.sortBy(fruits, 'name');\n  // => [{name:\"apple\", amount: 4}, {name:\"banana\", amount: 2}, {name:\"mango\", amount: 1}, {name:\"pineapple\", amount: 2}]\n\n  // Lodash\n  _.orderBy(fruits, ['name'],['asc']);\n  // => [{name:\"apple\", amount: 4}, {name:\"banana\", amount: 2}, {name:\"mango\", amount: 1}, {name:\"pineapple\", amount: 2}]\n\n  // Native\n  const sortBy = (key) => {\n    return (a, b) => (a[key] > b[key]) ? 1 : ((b[key] > a[key]) ? -1 : 0);\n  };\n\n  // The native sort modifies the array in place. `_.orderBy` and `_.sortBy` do not, so we use `.concat()` to\n  // copy the array, then sort.\n  fruits.concat().sort(sortBy(\"name\"));\n  // => [{name:\"apple\", amount: 4}, {name:\"banana\", amount: 2}, {name:\"mango\", amount: 1}, {name:\"pineapple\", amount: 2}]\n  ```\n\n#### Browser Support for `Array.prototype.concat()` and `Array.prototype.sort()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  1.0 ✔  | ✔ | 1.0 ✔ |  5.5 ✔  |  ✔  |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.uniq\n\nProduces a duplicate-free version of the array, using === to test object equality.\n\n  ```js\n  // Underscore/Lodash\n  var array = [1, 2, 1, 4, 1, 3]\n  var result = _.uniq(array)\n  console.log(result)\n  // output: [1, 2, 4, 3]\n\n  // Native\n  var array = [1, 2, 1, 4, 1, 3];\n  var result = [...new Set(array)];\n  console.log(result)\n  // output: [1, 2, 4, 3]\n  ```\n\n#### Browser Support for Spread in array literals\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n 46.0  ✔  | 12.0 ✔ | 16.0 ✔ |  ✖  |  37.0 ✔  |  8.0 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n## Function\n\n### _.after\n\n> [!WARNING]\n> This is an alternative implementation\n\nCreates a version of the function that will only be run after first being called count times. Useful for grouping asynchronous responses, where you want to be sure that all the async calls have finished, before proceeding.\n\n  ```js\n  var notes = ['profile', 'settings']\n  // Underscore/Lodash\n  var renderNotes = _.after(notes.length, render)\n  notes.forEach(function (note) {\n    console.log(note)\n    renderNotes()\n  })\n\n  // Native\n  notes.forEach(function (note, index) {\n    console.log(note)\n    if (notes.length === (index + 1)) {\n      render()\n    }\n  })\n  ```\n\n#### Browser Support for `Array.prototype.forEach()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n :-: | :-: | :-: | :-: | :-: | :-: |\n   ✔  |  ✔ |  1.5 ✔ |  9.0 ✔ |  ✔  | ✔  |\n\n **[⬆ back to top](#quick-links)**\n\n### _.bind\n\nCreate a new function that calls _func_ with _thisArg_ and _args_.\n\n  ```js\n  var objA = {\n    x: 66,\n    offsetX: function(offset) {\n      return this.x + offset;\n    }\n  }\n\n  var objB = {\n    x: 67\n  };\n\n  // Underscore/Lodash\n  var boundOffsetX = _.bind(objA.offsetX, objB, 0);\n\n  // Native\n  var boundOffsetX = objA.offsetX.bind(objB, 0);\n  ```\n\n#### Browser Support for `Function.prototype.bind()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  7.0 ✔  |  ✔ | 4.0 ✔ |  9.0 ✔ |  11.6 ✔ |  5.1 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isFunction\n\nChecks if value is classified as a _Function_ object.\n\n```js\n// Lodash\n_.isFunction(console.log);\n// => true\n\n_.isFunction(/abc/);\n// => false\n\n// Native\nfunction isFunction(func) {\n  return typeof func === \"function\";\n}\n\nisFunction(setTimeout);\n// => true\n\nisFunction(123);\n// => false\n```\n\n#### Browser Support\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.debounce\n\nCreate a new function that calls `func` with `thisArg` and `args`.\n\n  ```js\n  function debounce(func, wait, immediate) {\n\tvar timeout;\n\treturn function() {\n\t\tvar context = this, args = arguments;\n\t\tclearTimeout(timeout);\n\t\tif (immediate && !timeout) func.apply(context, args);\n\t\ttimeout = setTimeout(function() {\n\t\t\ttimeout = null;\n\t\t\tif (!immediate) func.apply(context, args);\n\t\t}, wait);\n\t};\n  }\n\n  // Avoid costly calculations while the window size is in flux.\n  jQuery(window).on('resize', debounce(calculateLayout, 150));\n  ```\n\n#### Browser Support for `debounce`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  7.0 ✔  |  ✔ | 4.0 ✔ |  9.0 ✔ |  11.6 ✔ |  5.1 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n\n### _.partial\n\nCreate a new function that calls `func` with `args`.\n\n  ```js\n  // Lodash\n  function greet(greeting, name) {\n    return greeting + ' ' + name;\n  }\n  var sayHelloTo = _.partial(greet, 'Hello');\n  var result = sayHelloTo('Jose')\n  console.log(result)\n  // output: 'Hello Jose'\n\n  // Native\n  function greet(greeting, name) {\n    return greeting + ' ' + name;\n  }\n  var sayHelloTo = (...args) => greet('Hello', ...args)\n  var result = sayHelloTo('Jose')\n  console.log(result)\n  // output: 'Hello Jose'\n\n  // Native\n  const partial = (func, ...boundArgs) => (...remainingArgs) => func(...boundArgs, ...remainingArgs)\n  var sayHelloTo = partial(greet, 'Hello');\n  var result = sayHelloTo('Jose')\n  console.log(result)\n  // output: 'Hello Jose'\n  ```\n\n#### Browser Support for Spread\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  46.0 ✔ | 12.0 ✔ | 16.0 ✔ |  ✖  |  37.0 ✔ |  8.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.throttle\n\nCreate a new function that limits calls to `func` to once every given timeframe.\n\n  ```js\n  function throttle(func, timeFrame) {\n    var lastTime = 0;\n    return function (...args) {\n        var now = new Date();\n        if (now - lastTime >= timeFrame) {\n            func(...args);\n            lastTime = now;\n        }\n    };\n  }\n\n  // Avoid running the same function twice within the specified timeframe.\n  jQuery(window).on('resize', throttle(calculateLayout, 150));\n  ```\n\n#### Browser Support for `throttle`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  5.0 ✔  |  12.0 ✔ | 3.0 ✔ |  9.0 ✔ |  10.5 ✔ |  4.0 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n\n## Lang\n\n### _.castArray\n\nPuts the value into an array of length one if it is not already an array.\n\n```js\n// Underscore\nconsole.log(_.castArray(5))\n// output: [5]\nconsole.log(_.castArray([2]))\n// output: [2]\n\n// Native\nfunction castArray(arr) {\n  return Array.isArray(arr) ? arr : [arr]\n}\n// output: true\nconsole.log(castArray(5));\n// output: [5]\nconsole.log(castArray([2]));\n// output: [2]\n```\n\n#### Browser Support for `Array.isArray()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n5.0 ✔  |  ✔  | 4.0 ✔  |  9.0 ✔  |  10.5 ✔  | 5.0 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.cloneDeep\nCreates a deep copy by recursively cloning the value.\n\n```js\n// Lodash\nvar objects = [{ 'a': 1 }, { 'b': 2 }];\n\nvar clone = _.cloneDeep(objects);\nconsole.log(clone[0] === objects[0]);\n// output: false\n\n// Native\nvar objects = [{ 'a': 1 }, { 'b': 2 }];\n\nvar clone = structuredClone(objects);\nconsole.log(clone[0] === objects[0]);\n// output: false\n```\n\n#### Browser Support for `structuredClone()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  98.0 ✔  | 98.0 ✔ | 94.0 ✔ |  ✖  |  84.0 ✔ |  15.4 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isDate\n\nChecks if value is classified as a Date object.\n\n```js\n// Lodash\nconsole.log(_.isDate(new Date));\n// output: true\n\n// Native\nconsole.log(Object.prototype.toString.call(new Date) === \"[object Date]\");\n// output: true\n```\n\n#### Browser Support for `String.prototype.toString.call()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | ✔ |  ✔  | ✔ | ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.gt\n\nChecks if value is greater than other.\n\n```js\n// Lodash\nconsole.log(_.gt(3, 1))\n// output: true\n\n// Native\nconsole.log(3 > 1);\n// output: true\n```\n\n#### Browser Support\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | ✔ |  ✔  | ✔ | ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.gte\n\nChecks if value is greater than or equal to other.\n\n```js\n// Lodash\nconsole.log(_.gte(3, 1))\n// output: true\n\n// Native\nconsole.log(3 >= 1);\n// output: true\n```\n\n#### Browser Support\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | ✔ |  ✔  | ✔ | ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isEmpty\n\nChecks if value is an empty object or collection.\n\n> [!WARNING]\n> The Native version does not support evaluating a Set or a Map\n\n  ```js\n  // Lodash\n  console.log(_.isEmpty(null))\n  // output: true\n  console.log(_.isEmpty(''))\n  // output: true\n  console.log(_.isEmpty({}))\n  // output: true\n  console.log(_.isEmpty([]))\n  // output: true\n  console.log(_.isEmpty({a: '1'}))\n  // output: false\n\n  // Native\n  const isEmpty = obj => [Object, Array].includes((obj || {}).constructor) && !Object.entries((obj || {})).length;\n\n  console.log(isEmpty(null))\n  // output: true\n  console.log(isEmpty(''))\n  // output: true\n  console.log(isEmpty({}))\n  // output: true\n  console.log(isEmpty([]))\n  // output: true\n  console.log(isEmpty({a: '1'}))\n  // output: false\n  ```\n\n#### Browser Support for `Array.prototype.includes()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n   47.0 ✔  | 14.0 ✔ | 43.0 ✔ |  ✖ |  34.0 ✔ |  9.0 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isFinite\n\nChecks if value is a finite primitive number.\n\n  ```js\n  // Lodash\n  console.log(_.isFinite('3'))\n  // output: false\n  console.log(_.isFinite(3))\n  // output: true\n\n  // Native\n  console.log(Number.isFinite('3'))\n  // output: false\n  console.log(Number.isFinite(3))\n  // output: true\n  ```\n\n#### Browser Support for `Number.isFinite()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  19.0 ✔  |  ✔ | 16.0 ✔ |  ✖  |  15.0 ✔ |  9.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isInteger\n\nChecks if value is an integer.\n\n  ```js\n  // Lodash\n  console.log(_.isInteger(3))\n  // output: true\n  console.log(_.isInteger('3'))\n  // output: false\n\n  // Native\n  console.log(Number.isInteger(3))\n  // output: true\n  console.log(Number.isInteger('3'))\n  // output: false\n  ```\n\n#### Browser Support for `Number.isInteger()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  |  12 ✔ | 16.0 ✔ |  ✖  |  ✔ |  ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isPlainObject\n\nChecks if value is a plain object, that is, an object created by the Object constructor or one with a [[Prototype]] of null.\n\n  ```js\n  var object = { 'a': 1, 'b': 2, 'c': 1 };\n\n  // Underscore/Lodash\n  var result = _.isPlainObject(object);\n  console.log(result)\n  // output: true\n\n  function isPlainObject(value) {\n    if (typeof value !== 'object' || value === null) return false\n\n    if (Object.prototype.toString.call(value) !== '[object Object]') return false\n\n    const proto = Object.getPrototypeOf(value);\n    if (proto === null) return true\n\n    const Ctor = Object.prototype.hasOwnProperty.call(proto, 'constructor') && proto.constructor;\n    return (\n        typeof Ctor === 'function' &&\n        Ctor instanceof Ctor && Function.prototype.call(Ctor) === Function.prototype.call(value)\n    );\n  }\n  ```\n\n#### Browser Support for `Object.getPrototypeOf()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  5.0 ✔  | 12.0 ✔  | 3.5 ✔ |  ✖  |  12.1 ✔ |  5.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isNaN\n\nChecks if a value is NaN.\n\n  ```js\n  // Underscore/Lodash\n  console.log(_.isNaN(NaN))\n  // output: true\n\n  // Native\n  console.log(isNaN(NaN))\n  // output: true\n\n  // ES6\n  console.log(Number.isNaN(NaN))\n  // output: true\n  ```\n\nMDN:\n> In comparison to the global `isNaN()` function, `Number.isNaN()` doesn't suffer the problem of forcefully converting the parameter to a number. This means it is now safe to pass values that would normally convert to `NaN`, but aren't actually the same value as `NaN`. This also means that only values of the type number, that are also `NaN`, return true. [Number.isNaN()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN)\n\nVoice from the Lodash author:\n\n> Lodash's `_.isNaN` is equiv to ES6 `Number.isNaN` which is different than the global `isNaN`.\n> --- [jdalton](https://github.com/cht8687/You-Dont-Need-Lodash-Underscore/commit/b8559a603dccaaa2449b5a68a2d8325cf1fb29cd#)\n\n#### Browser Support for `isNaN`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ |  1.0 ✔ |  ✔ |  ✔ |  ✔  |\n\n#### Browser Support for `Number.isNaN`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  25.0 ✔ | ✔ |  15.0 ✔ |  ✖ |  ✔ |  9.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isNil\n\n> [!WARNING]\n> Not in Underscore.js\n\nChecks if value is null or undefined.\n\n```js\n// Lodash\nconsole.log(_.isNil(null))\n// output: true\nconsole.log(_.isNil(NaN))\n// output: false\nconsole.log(_.isNil(undefined))\n// output: true\n\n// Native\nconsole.log(null == null);\n// output: true\nconsole.log(NaN == null);\n// output: false\nconsole.log(undefined == null)\n// output: true\n```\n\n#### Browser Support\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  |  ✔ | ✔ |  ✔  | ✔ | ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isNull\n\nChecks if value is null.\n\n```js\n// Underscore/Lodash\nconsole.log(_.isNull(null))\n// output: true\nconsole.log(_.isNull(void 0))\n// output: false\n\n// Native\nconsole.log(null === null);\n// output: true\nconsole.log(void 0 === null);\n// output: false\n```\n\n#### Browser Support\n\n![Chrome][chrome-image] |  ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  |  ✔ | ✔ |  ✔  | ✔ | ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isUndefined\n\nChecks if value is undefined.\n\n```js\n// Underscore/Lodash\nconsole.log(_.isUndefined(a))\n// output: true\n\n// Native\nconsole.log(typeof a === 'undefined');\n// output: true\nconsole.log(a === undefined);\n// output: true\n```\n\n#### Browser Support\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 1 ✔ |  ✔  | ✔ | ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n## Object\n\n### _.assign\n\nThe method is used to copy the values of all enumerable own properties from one or more source objects to a target object.\n\n  ```js\n  // Underscore: _.extendOwn\n  // Lodash\n  function Foo() {\n    this.c = 3;\n  }\n  function Bar() {\n    this.e = 5;\n  }\n  Foo.prototype.d = 4;\n  Bar.prototype.f = 6;\n  var result = _.assign(new Foo, new Bar);\n  console.log(result);\n  // output: { 'c': 3, 'e': 5 }\n\n  // Native\n  function Foo() {\n    this.c = 3;\n  }\n  function Bar() {\n    this.e = 5;\n  }\n  Foo.prototype.d = 4;\n  Bar.prototype.f = 6;\n  var result = Object.assign({}, new Foo, new Bar);\n  console.log(result);\n  // output: { 'c': 3, 'e': 5 }\n  ```\n\n#### Browser Support for `Object.assign()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  45.0 ✔  | ✔ | 34.0 ✔ |  ✖  |  32.0 ✔ |  9.0 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.defaults\n\nThe method is used to apply new values over an object with default values for keys.\n\n  ```js\n  // Underscore: _.defaults\n  // Lodash\n  const newValues = {a: 3};\n  const defaultValues = {a: 1, b: 2}\n  const appliedValues = _.defaults(newValues, defaultValues);\n  console.log(appliedValues)\n  // output { a: 3, b: 2 }\n\n  // Native\n  const newValues = {a: 3};\n  const defaultValues = {a: 1, b: 2}\n  const appliedValues = Object.assign({}, defaultValues, newValues);\n  // output { a: 3, b: 2 }\n  ```\n\n#### Browser Support for `Object.assign()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  45.0 ✔  | ✔ | 34.0 ✔ |  ✖  |  32.0 ✔ |  9.0 ✔  |\n\n **[⬆ back to top](#quick-links)**\n\n### _.extend\n\nThe method is used to copy the values of all enumerable own and inherited properties from one or more source objects to a target object.\n\n  ```js\n  // Underscore\n  // Lodash: _.assignIn\n  function Foo() {\n    this.c = 3;\n  }\n  function Bar() {\n    this.e = 5;\n  }\n  Foo.prototype.d = 4;\n  Bar.prototype.f = 6;\n  var result = _.extend({}, new Foo, new Bar);\n  console.log(result);\n  // output: { 'c': 3, 'd': 4, 'e': 5, 'f': 6 }\n\n  // Native\n  function Foo() {\n    this.c = 3;\n  }\n  function Bar() {\n    this.e = 5;\n  }\n  Foo.prototype.d = 4;\n  Bar.prototype.f = 6;\n  var result = Object.assign({}, new Foo, Foo.prototype, new Bar, Bar.prototype);\n  console.log(result);\n  // output: { 'c': 3, 'd': 4, 'e': 5, 'f': 6 }\n\n  //Or using a function\n  const extend = (target, ...sources) => {\n   const length = sources.length;\n\n    if (length < 1 || target == null) return target;\n    for (let i = 0; i < length; i++) {\n      const source = sources[i];\n\n      for (const key in source) {\n        target[key] = source[key];\n      }\n    }\n    return target;\n  };\n  console.log(extend({}, new Foo, new Bar));\n  // output: { 'c': 3, 'd': 4, 'e': 5, 'f': 6 }\n  ```\n\n#### Browser Support for `Object.assign()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  45.0 ✔  | ✔ | 34.0 ✔ |  ✖  |  32.0 ✔ |  9.0 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.has\n\nChecks if `key` is a direct property of `object`. Key may be a path of a value separated by `.`\n\n  ```js\n  // Lodash\n  var object = { a: 1, b: 'settings', c: { d: 'test' } };\n\n  var hasA = _.has(object, 'a');\n  var hasCWhichHasD = _.has(object, 'c.d')\n\n  console.log(hasA);\n  // output: true\n  console.log(hasCWhichHasD);\n  // output: true\n\n  // Native\n  const has = function (obj, key) {\n    var keyParts = key.split('.');\n\n    return !!obj && (\n      keyParts.length > 1\n        ? has(obj[key.split('.')[0]], keyParts.slice(1).join('.'))\n        : hasOwnProperty.call(obj, key)\n    );\n  };\n\n  var object = { a: 1, b: 'settings' };\n  var result = has(object, 'a');\n  // output: true\n  ```\n\n#### Browser Support for Object .hasOwnProperty\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | 12 ✔ |  ✔ |  5.5 ✔ |  5 ✔ |  3 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.get\n\nGets the value at path of object.\n\n> [!NOTE]\n> If provided path does not exist inside the object js will generate error.\n\n  ```js\n  // Lodash\n  var object = { a: [{ b: { c: 3 } }] };\n  var result = _.get(object, 'a[0].b.c', 1);\n  console.log(result);\n  // output: 3\n\n  // Native (ES6 - IE not supported)\n  var object = { a: [{ b: { c: 3 } }] };\n  var { a: [{ b: { c: result = 1 } = {} } = {}] = [] } = object;\n  console.log(result);\n  // output: 3\n\n  // Native (ES11)\n  var object = { a: [{ b: { c: 3 } }] };\n  var result = object?.a?.[0]?.b?.c ?? 1;\n  console.log(result);\n  // output: 3\n\n  // Native\n  const get = (obj, path, defaultValue = undefined) => {\n    const travel = regexp =>\n      String.prototype.split\n        .call(path, regexp)\n        .filter(Boolean)\n        .reduce((res, key) => (res !== null && res !== undefined ? res[key] : res), obj);\n    const result = travel(/[,[\\]]+?/) || travel(/[,[\\].]+?/);\n    return result === undefined || result === obj ? defaultValue : result;\n  };\n\n  var object = { a: [{ b: { c: 3 } }] };\n  var result = get(object, 'a[0].b.c', 1);\n  // output: 3\n  ```\n\n#### Browser Support for Object destructing\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  49.0 ✔  | 14.0 ✔ |  41.0 ✔ |  ✖  |  41.0 ✔ |  8.0 ✔ |\n\n#### Browser Support for optional chaining `?.`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  80.0 ✔  | 80.0 ✔ |  74.0 ✔ |  ✖  |  67.0 ✔ |  13.1 ✔ |\n\n#### Browser Support for nullish coalescing operator `??`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  80.0 ✔  | 80.0 ✔ |  72.0 ✔ |  ✖  |  ✖ |  13.1 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.invert\n\nCreates an object composed of the inverted keys and values of object. If object contains duplicate values, subsequent values overwrite property assignments of previous values.\n\n  ```js\n  var object = { 'a': 1, 'b': 2, 'c': 1 };\n\n  // Underscore/Lodash\n  var result = _.invert(object);\n  console.log(result)\n  // output: { '1': 'c', '2': 'b' }\n\n  // Native (IE6)\n  function invert(object) {\n    var obj = {};\n    for (var key in object) {\n      if (object.hasOwnProperty(key)) {\n        obj[object[key]] = key;\n      }\n    }\n    return obj;\n  }\n  var result = invert(object);\n  console.log(result)\n  // output: { '1': 'c', '2': 'b' }\n\n  // Native (IE not supported)\n  const invert = object => Object.entries(object)\n    .reduce((acc, current) => {\n      acc[current[1]] = current[0];\n      return acc;\n    }, {}\n  );\n  ```\n#### Browser Support\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  4.0 ✔ | ✔ | 2.0 ✔ |  6.0 ✔  |  10.0 ✔ | 3.1 ✔ |\n\n#### Browser Support for `Object.entries()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  54.0 ✔  | 14.0 ✔  | 47.0 ✔ |  ✖  |  41.0 ✔ |  10.1 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.keys\n\nRetrieves all the names of the object's own enumerable properties.\n\n  ```js\n  // Underscore/Lodash\n  var result = _.keys({one: 1, two: 2, three: 3})\n  console.log(result)\n  // output: [\"one\", \"two\", \"three\"]\n\n  // Native\n  var result2 = Object.keys({one: 1, two: 2, three: 3})\n  console.log(result2)\n  // output: [\"one\", \"two\", \"three\"]\n  ```\n\n#### Browser Support for `Object.keys()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: |  :-: |\n  5.0 ✔  | ✔ | 4.0 ✔ |  9.0 ✔ |  12.0 ✔ |  5.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.mapKeys\n\nThe opposite of _.mapValues; this method creates an object with the same values as object and keys generated by running each own enumerable string keyed property of object thru iteratee. The iteratee is invoked with three arguments: (value, key, object).\n\n  ```js\n  // Lodash\n  var result = _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {\n    return key + value;\n  });\n  console.log(result)\n  // output: { 'a1': 1, 'b2': 2 }\n\n  // Native (IE6)\n  function mapKeys(object, cb) {\n    var obj = {};\n    for (var key in object) {\n      if (object.hasOwnProperty(key)) {\n          var newKey = cb(object[key], key, object);\n          obj[newKey] = object[key];\n      }\n    }\n    return obj;\n  }\n  var result = mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {\n    return key + value;\n  });\n  console.log(result)\n  // output: { 'a1': 1, 'b2': 2 }\n\n  // Native (IE not supported)\n    const mapKeys = (object, cb) => Object.entries(object)\n      .reduce((acc, current) => {\n        const newKey = cb(current[1], current[0], object);\n        acc[newKey] = current[1];\n        return acc;\n      }, {}\n  );\n  const result2 = mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {\n    return key + value;\n  });\n  console.log(result2)\n  // output: { 'a1': 1, 'b2': 2 }\n  ```\n#### Browser Support\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  4.0 ✔ | ✔ | 2.0 ✔ |  6.0 ✔  |  10.0 ✔ | 3.1 ✔ |\n\n#### Browser Support for `Object.entries()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  54.0 ✔  | 14.0 ✔  | 47.0 ✔ |  ✖  |  41.0 ✔ |  10.1 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.omit\n\nReturns a copy of the object, filtered to omit the keys specified.\n\n  ```js\n  var object = { 'a': 1, 'b': '2', 'c': 3 };\n\n  // Underscore/Lodash\n  var result = _.omit(object, ['a', 'c']);\n  console.log(result)\n  // output: { 'b': '2' }\n\n  // Native\n  var { a, c, ...result2 } = object;\n  console.log(result2)\n  // output: { 'b': '2' }\n  ```\n\n#### Browser Support for Spread in object literals\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  60.0 ✔ | 79 ✔ | 55.0 ✔ |  ✖ |  37.0 ✔ | ✖ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.pick\n\nCreates an object composed of the object properties predicate returns truthy for.\n\n  ```js\n  var object = { 'a': 1, 'b': '2', 'c': 3 };\n\n  // Underscore/Lodash\n  var result = _.pick(object, ['a', 'c', 'x']);\n  console.log(result)\n  // output: {a: 1, c: 3}\n\n  // Native\n  function pick(object, keys) {\n    return keys.reduce((obj, key) => {\n       if (object && object.hasOwnProperty(key)) {\n          obj[key] = object[key];\n       }\n       return obj;\n     }, {});\n  }\n  var result = pick(object, ['a', 'c', 'x']);\n  console.log(result)\n  // output: {a: 1, c: 3}\n  ```\n\n#### Browser Support\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  38.0 ✔ | ✔ | 13.0 ✔ |  12.0 ✔  |  25.0 ✔ | 7.1 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.pickBy\n\nCreates an object composed of the object properties predicate returns truthy for.\n\n  ```js\n  var object = { 'a': 1, 'b': null, 'c': 3, 'd': false, 'e': undefined };\n\n  // Underscore/Lodash\n  var result = _.pickBy(object);\n  console.log(result)\n  // output: {a: 1, c: 3}\n\n  // Native\n  function pickBy(object) {\n      const obj = {};\n      for (const key in object) {\n          if (object[key]) {\n              obj[key] = object[key];\n          }\n      }\n      return obj;\n  }\n  var result = pickBy(object);\n  console.log(result)\n  // output: {a: 1, c: 3}\n  ```\n\n#### Browser Support\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: |  :-: |\n  ✔  | ✔ |  ✔ | 6.0 ✔  | ✔ | ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.toPairs\n\nRetrieves all the given object's own enumerable property `[ key, value ]` pairs.\n\n  ```js\n  // Underscore - also called _.pairs\n  // Lodash - also called _.entries\n  var result = _.toPairs({one: 1, two: 2, three: 3})\n  console.log(result)\n  // output: [[\"one\", 1], [\"two\", 2], [\"three\", 3]]\n\n  // Native\n  var result2 = Object.entries({one: 1, two: 2, three: 3})\n  console.log(result2)\n  // output: [[\"one\", 1], [\"two\", 2], [\"three\", 3]]\n  ```\n\n#### Browser Support for `Object.entries()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  54.0 ✔  | 14.0 ✔  | 47.0 ✔ |  ✖  |  41.0 ✔ |  10.1 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.values\n\nRetrieves all the given object's own enumerable property values.\n\n  ```js\n  // Underscore/Lodash\n  var result = _.values({one: 1, two: 2, three: 3})\n  console.log(result)\n  // output: [1, 2, 3]\n\n  // Native\n  var result2 = Object.values({one: 1, two: 2, three: 3})\n  console.log(result2)\n  // output: [1, 2, 3]\n  ```\n\n#### Browser Support for `Object.values()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  54.0 ✔  | 14.0 ✔ |  47.0 ✔ |  ✖  |  41.0 ✔ |  10.1 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n## String\n\n### _.capitalize\n\n> [!WARNING]\n> Not in Underscore.js\n\nConverts the first character of string to upper case and the remaining to lower case.\n\n  ```js\n  // Lodash\n  var result = _.capitalize('FRED');\n  console.log(result);\n  // => 'Fred'\n\n  // Native\n  const capitalize = (string) => {\n    return string ? string.charAt(0).toUpperCase() + string.slice(1).toLowerCase() : '';\n  };\n\n  var result = capitalize('FRED');\n  console.log(result);\n  // => 'Fred'\n  ```\n\n#### Browser Support\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.endsWith\n\n> [!WARNING]\n> Not in Underscore.js\n\nChecks if string ends with the given target string.\n\n  ```js\n  // Lodash\n  _.endsWith('abc', 'c');\n  // => true\n\n  _.endsWith('abc', 'b');\n  // => false\n\n  _.endsWith('abc', 'b', 2);\n  // => true\n\n  // Native\n  'abc'.endsWith('c');\n  // => true\n\n  'abc'.endsWith('b');\n  // => false\n\n  'abc'.endsWith('b', 2);\n  // => true\n  ```\n\n#### Browser Support for `String.prototype.endsWith()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  41.0 ✔  |  ✔ | 17.0 ✔ |  ✖  |  28.0 ✔ |  9.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.isString\n\nChecks if value is classified as a String primitive or object.\n\n  ```js\n  // Lodash\n  _.isString('abc');\n  // => true\n\n  _.isString(123);\n  // => false\n\n  // Native\n  function isString(str){\n    if (str != null && typeof str.valueOf() === \"string\") {\n      return true\n    }\n    return false\n  }\n\n  isString('abc');\n  // => true\n\n  isString(123);\n  // => false\n  ```\n\n#### Browser Support\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.lowerFirst\n\n> [!WARNING]\n> Not in Underscore.js\n\nConverts the first character of string to lower case.\n\n  ```js\n  // Lodash\n  var result = _.lowerFirst('Fred')\n  console.log(result)\n  // output: 'fred'\n\n  // Native\n  const lowerFirst = (string) => {\n    return string ? string.charAt(0).toLowerCase() + string.slice(1) : ''\n  }\n\n  var result = lowerFirst('Fred')\n  console.log(result)\n  // output: 'fred'\n  ```\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ |  ✔ |  ✔  |  ✔ |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.padStart and _.padEnd\n\n> [!WARNING]\n> Not in Underscore.js\n\nPads the current string with another string (multiple times, if needed) until the resulting string reaches the given length.\n\n  ```js\n  // Lodash\n  console.log(_.padStart('123', 5, '0'))\n  // output: '00123'\n\n  console.log(_.padEnd('123', 5, '0'))\n  // output: '12300'\n\n  // Native\n  console.log('123'.padStart(5, '0'))\n  // output: '00123'\n\n  console.log('123'.padEnd(5, '0'))\n  // output: '12300'\n  ```\n\n#### Browser Support for `String.prototype.padStart()` and `String.prototype.padEnd()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  57.0 ✔  |  15.0 ✔ | 48.0 ✔ |  ✖  |  44.0 ✔ |  10.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.repeat\n\n> [!WARNING]\n> Not in Underscore.js\n\nRepeats the given string n times.\n\n  ```js\n  // Lodash\n  var result = _.repeat('abc', 2)\n  console.log(result)\n  // output: 'abcabc'\n\n  // Native\n  var result = 'abc'.repeat(2)\n  console.log(result)\n  // output: 'abcabc'\n  ```\n\n#### Browser Support for `String.prototype.repeat()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  41.0 ✔  | ✔ | 24.0 ✔ |  ✖  |  28.0 ✔ |  9.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.replace\n\nReturns a new string with some or all matches of a `pattern` replaced by a `replacement`.\n\n  ```js\n  // Lodash\n  var re = /apples/gi;\n  var str = 'Apples are round, and apples are juicy.';\n  var newstr = _.replace(str, re, 'oranges');\n  console.log(newstr);\n  // output: 'oranges are round, and oranges are juicy.'\n\n  // Native\n  var re = /apples/gi;\n  var str = 'Apples are round, and apples are juicy.';\n  var result = str.replace(re, 'oranges');\n  console.log(result);\n  // output: 'oranges are round, and oranges are juicy.'\n  ```\n\n#### Browser Support for `String.prototype.replace()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ | 1.0 ✔ |  ✔  |  ✔ |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.split\n\n> [!WARNING]\n> Not in Underscore.js\n\nSplits string by separator.\n\n  ```js\n  // Lodash\n  var result = _.split('a-b-c', '-', 2)\n    console.log(result)\n  // output: ['a','b']\n\n  // Native\n  var result = 'a-b-c'.split('-', 2)\n  console.log(result)\n  // output: ['a','b']\n  ```\n\n#### Browser Support for `String.prototype.split()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ |  1.0 ✔ |  ✔  | ✔ | ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.startsWith\n\n> [!WARNING]\n> Not in Underscore.js\n\nChecks if string starts with the given target string.\n\n  ```js\n  // Lodash\n  var result = _.startsWith('abc', 'b', 1)\n  console.log(result)\n  // output: true\n\n  // Native\n  var result = 'abc'.startsWith('b', 1)\n  console.log(result)\n  // output: true\n  ```\n\n#### Browser Support for `String.prototype.startsWith()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  41.0 ✔  |  ✔ | 17.0 ✔ |  ✖  |  28.0 ✔ |  9.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n### _.template\n\n> [!NOTE]\n> This is an alternative implementation. Native template literals not escape html.\n\nCreate a template function.\n\n  ```js\n  // Lodash/Underscore\n  const compiled = _.template('hello <%= user %>!');\n  var result = compiled({ 'user': 'fred' });\n  console.log(result);\n  // output: 'hello fred'\n\n  // Native\n  const templateLiteral = (value) => `hello ${value.user}`;\n  var result = templateLiteral({ 'user': 'fred' });\n  console.log(result);\n  // output: 'hello fred'\n  ```\n\n#### Browser Support for String (template) literals\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  41.0 ✔  | 12.0 ✔ | 34.0 ✔ |  ✖  |  28.0 ✔ |  9.0 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.toLower\n\n> [!WARNING]\n> Not in Underscore.js\n\nLowercases a given string.\n\n  ```js\n  // Lodash\n  var result = _.toLower('FOOBAR')\n  console.log(result)\n  // output: 'foobar'\n\n  // Native\n  var result = 'FOOBAR'.toLowerCase()\n  console.log(result)\n  // output: 'foobar'\n  ```\n\n#### Browser Support for `String.prototype.toLowerCase()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  |  ✔ | 1.0 ✔ |  ✔  |  ✔ |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.toUpper\n\n> [!WARNING]\n> Not in Underscore.js\n\nUppercases a given string.\n\n  ```js\n  // Lodash\n  var result = _.toUpper('foobar')\n  console.log(result)\n  // output: 'FOOBAR'\n\n  // Native\n  var result = 'foobar'.toUpperCase()\n  console.log(result)\n  // output: 'FOOBAR'\n  ```\n\n#### Browser Support for `String.prototype.toUpperCase()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  |  ✔ | 1.0 ✔ |  ✔  |  ✔ |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.trim\n\n> [!WARNING]\n> Not in Underscore.js\n\nRemoves the leading and trailing whitespace characters from a string.\n\n  ```js\n  // Lodash\n  var result = _.trim(' abc ')\n  console.log(result)\n  // output: 'abc'\n\n  // Native\n  var result = ' abc '.trim()\n  console.log(result)\n  // output: 'abc'\n  ```\n\n#### Browser Support for `String.prototype.trim()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  5.0 ✔  | ✔ |  3.5 ✔ |  9.0 ✔  |  10.5 ✔ |  5.0 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.upperFirst\n\n> [!WARNING]\n> Not in Underscore.js\n\nUppercases the first letter of a given string.\n\n  ```js\n  // Lodash\n  var result = _.upperFirst('george')\n  console.log(result)\n  // output: 'George'\n\n  // Native\n  const upperFirst = (string) => {\n    return string ? string.charAt(0).toUpperCase() + string.slice(1) : ''\n  }\n\n  var result = upperFirst('george')\n  console.log(result)\n  // output: 'George'\n  ```\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  | ✔ |  ✔ |  ✔  |  ✔ |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n## Reference\n\n* [Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference)\n* [Underscore.js](http://underscorejs.org)\n* [Lodash.js](https://lodash.com/docs)\n\n**[⬆ back to top](#quick-links)**\n\n### _.uniqWith\n\nSimilar to `_.uniq` except that it accepts comparator which is invoked to compare elements of array. The order of result values is determined by the order they occur in the array.\n\n  ```js\n  // Lodash\n  const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];\n  const result = _.uniqWith(objects, _.isEqual);\n  console.log(result);\n  // output: [{ x: 1, y: 2 }, { x: 2, y: 1 }]\n\n  // Native\n  const uniqWith = (arr, fn) => arr.filter((element, index) => arr.findIndex((step) => fn(element, step)) === index);\n\n  const array = [1, 2, 2, 3, 4, 5, 2];\n  const result = uniqWith(array, (a, b) => a === b);\n  console.log(result);\n  // output: [1, 2, 3, 4, 5]\n\n  const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];\n  const result = uniqWith(objects, (a, b) => JSON.stringify(a) === JSON.stringify(b));\n  console.log(result);\n  // output: [{ x: 1, y: 2 }, { x: 2, y: 1 }]\n  ```\n\n### Browser Support for `Array.prototype.filter()` and `Array.prototype.findIndex()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n 45.0  ✔  | 12.0 ✔ | 25.0 ✔ |  ✖  |  32.0 ✔  |  8.0 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n## Util\n\n### _.times\n\nInvokes the iteratee n times, returning an array of the results of each invocation.\n\n  ```js\n  // Lodash\n  var result = _.times(10)\n  console.log(result)\n  // output: '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'\n\n  // Native\n  var result = Array.from({length: 10}, (_,x) => x)\n  console.log(result)\n  // output: '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'\n\n  // Native\n  var result = [...Array(10).keys()]\n  console.log(result)\n  // output: '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'\n  ```\n\n#### Browser Support for `Array.from()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  45.0 ✔  | ✔ |  32.0 ✔ |  ✖  |  ✔ | 9.0 ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n## Number\n\n### _.clamp\n\nClamps number within the inclusive lower and upper bounds.\n\n```js\n// Lodash\n_.clamp(-10, -5, 5);\n// => -5\n\n_.clamp(10, -5, 5);\n// => 5\n\n_.clamp(10, -5);\n// => -5\n\n_.clamp(10, 99);\n// => 10\n\n// Native\nconst clamp = (number, boundOne, boundTwo) => {\n  if (!boundTwo) {\n    return Math.max(number, boundOne) === boundOne ? number : boundOne;\n  } else if (Math.min(number, boundOne) === number) {\n    return boundOne;\n  } else if (Math.max(number, boundTwo) === number) {\n    return boundTwo;\n  }\n  return number;\n};\n\nclamp(-10, -5, 5);\n// => -5\n\nclamp(10, -5, 5);\n// => 5\n\nclamp(10, -5);\n// => -5\n\nclamp(10, 99);\n// => 10\n```\n\n#### Browser Support for `Math.min() and Math.max()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n✔  |  ✔  |  ✔  |  ✔  |  ✔  |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.inRange\n\nChecks if n is between start and up to, but not including, end. If end is not specified, it's set to start with start then set to 0. If start is greater than end the params are swapped to support negative ranges.\n\n  ```js\n    // Lodash\n    _.inRange(3, 2, 4);\n    // output: true\n    _.inRange(-3, -2, -6);\n    // output: true\n\n    //Native\n    const inRange = (num, init, final) => {\n      if(final === undefined){\n        final = init;\n        init = 0;\n      }\n      return (num >= Math.min(init, final) && num < Math.max(init, final));\n    }\n\n    //Native\n    const inRange = (num, a, b=0) => (Math.min(a,b) <= num && num < Math.max(a,b));\n\n    inRange(3, 2, 4);\n    // output: true\n    inRange(-3, -2, -6);\n    // output: true\n  ```\n\n#### Browser Support for `Math.min() and Math.max()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n✔  |  ✔  |  ✔  |  ✔  |  ✔  |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n### _.random\n\nProduces a random number between the inclusive lower and upper bounds. If only one argument is provided a number between 0 and the given number is returned. If floating is true, or either lower or upper are floats, a floating-point number is returned instead of an integer.\n\n  ```js\n    // Lodash\n    _.random(0, 5);\n    // => an integer between 0 and 5\n\n    _.random(5);\n    // => also an integer between 0 and 5\n\n    _.random(5, true);\n    // => a floating-point number between 0 and 5\n\n    _.random(1.2, 5.2);\n    // => a floating-point number between 1.2 and 5.2\n\n    //Native ES6\n    const random = (a = 1, b = 0) => {\n      const lower = Math.min(a, b);\n      const upper = Math.max(a, b);\n      return lower + Math.random() * (upper - lower);\n    };\n\n    const randomInt = (a = 1, b = 0) => {\n      const lower = Math.ceil(Math.min(a, b));\n      const upper = Math.floor(Math.max(a, b));\n      return Math.floor(lower + Math.random() * (upper - lower + 1))\n    };\n\n    random();\n    // => a floating-point number between 0 and 1\n\n    random(5);\n    // => a floating-point number between 0 and 5\n\n    random(0, 5);\n    // => also a floating-point number between 0 and 5\n\n    random(1.2, 5.2);\n    // => a floating-point number between 1.2 and 5.2\n\n    randomInt();\n    // => just 0 or 1\n\n    randomInt(5);\n    // => an integer between 0 and 5\n\n    randomInt(0, 5);\n    // => also an integer between 0 and 5\n\n    randomInt(1.2, 5.2);\n    // => an integer between 2 and 5\n\n  ```\n\n#### Browser Support for `Math.random()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  ✔  |  ✔  |  ✔  |  ✔  |  ✔  |  ✔  |\n\n**[⬆ back to top](#quick-links)**\n\n\n## Inspired by:\n\n* [You-Dont-Need-jQuery](https://github.com/oneuijs/You-Dont-Need-jQuery)\n* [Rui's blog](http://ktei.github.io/2016/01/07/some-general-js-tips-1.html)\n\n\n## License\n\nMIT\n\n[chrome-image]: https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png\n[firefox-image]: https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png\n[ie-image]: https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png\n[opera-image]: https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png\n[safari-image]: https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png\n[edge-image]: https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png\n"
  },
  {
    "path": "TEMPLATE.md",
    "content": "## Quick Links\n\n**[Section](#section)**\n\n1. [_.sortYourMethodAlphabetically](#_sortYourMethodAlphabetically) \n\n\n\n\n\n\n\n\n\n### _.sortYourMethodAlphabetically\nExplains or copy/paste lodash/underscore description.\n\n  ```js\n  // Lodash\n  var result = _.sortYourMethodAlphabetically('abc', ...)\n  console.log(result)\n  // output: true\n\n  // Native\n  var result = 'abc'.sortYourMethodAlphabetically(...)\n  console.log(result)\n  // output: true\n  ```\n\n#### Browser Support for `Array.prototype.sortYourMethodAlphabetically()`\n\n![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image]\n:-: | :-: | :-: | :-: | :-: | :-: |\n  41.0 ✔  | 15.0 ✔ | 17.0 ✔ |  ✖  |  10.5 ✔ |  9.0 ✔ |\n\n**[⬆ back to top](#quick-links)**\n\n\n\n\n\n\n\n\n> !------ DO NOT COPY THESE LINES BELOW -------------!\n> For Browser support, visit [MDN web docs](https://developer.mozilla.org/en-US/), search for a term there and see the bottom section of the page.\n\n[chrome-image]: https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png\n[firefox-image]: https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png\n[ie-image]: https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png\n[opera-image]: https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png\n[safari-image]: https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png\n[edge-image]:\nhttps://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png\n"
  },
  {
    "path": "configuring.md",
    "content": "## Configuring the ESLint Plugin\n\n\n### If you haven't already, add ESLint to your project\n\n```sh\nnpm install --save-dev eslint\n```\n\n### Add the plugin\n\n```sh\nnpm install --save-dev eslint-plugin-you-dont-need-lodash-underscore\n```\n\n### Add the plugin to your .eslintrc.js file\n\n```js\n\"plugins\": [\"you-dont-need-lodash-underscore\"],\n```\n\nIf you already have plugins installed, just add to the array.\n\n```js\n\"plugins\": [\"react\", \"you-dont-need-lodash-underscore\"],\n```\n\n### Now configure your plugin.\n\nYou can enable or disable individual rules.\n\n```js\n\"rules\": {\n  \"you-dont-need-lodash-underscore/for-each\": \"error\",\n  \"you-dont-need-lodash-underscore/concat\": \"warn\",\n  \"you-dont-need-lodash-underscore/map\": \"off\",\n  ...\n}\n```\n\nTo save the trouble of configuring each rule individually, you can start by extending one of the\ndefault configurations, and then override individual rules as desired.\n\n```js\n\"extends\" : [\"plugin:you-dont-need-lodash-underscore/compatible\"],\n```\n\nThe following options are available:\n\n- you-dont-need-lodash-underscore:all-warn (all rules set to warn)\n- you-dont-need-lodash-underscore:all (all rules set to error)\n- you-dont-need-lodash-underscore:compatible-warn (rules in which the native implementation is perfectly compatible with the _ one are set to warn, the rest are disabled)\n- you-dont-need-lodash-underscore:compatible (rules in which the native implementation is perfectly compatible with _ one are set to error, the rest are set to warn)\n\n\nFor more information, see the [ESLint documentation](http://eslint.org/docs/user-guide/configuring).\n"
  },
  {
    "path": "docs/.nojekyll",
    "content": ""
  },
  {
    "path": "docs/README.md",
    "content": "[remoteMarkdownUrl](https://raw.githubusercontent.com/you-dont-need/You-Dont-Need-Lodash-Underscore/master/README.md)"
  },
  {
    "path": "docs/index.html",
    "content": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n  <meta charset=\"UTF-8\">\r\n  <title>You don’t (may not) need Lodash/Underscore</title>\r\n  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\r\n  <meta name=\"description\" content=\"Description\">\r\n  <meta name=\"viewport\" content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\r\n  <link rel=\"stylesheet\" href=\"//cdn.jsdelivr.net/npm/docsify/lib/themes/vue.css\">\r\n</head>\r\n<body>\r\n  <div id=\"app\"></div>\r\n  <script>\r\n    window.$docsify = {\r\n      name: 'You don\\'t need Lodash',\r\n      nameLink: '/',\r\n      repo: 'https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore',\r\n      autoHeader: true,\r\n      maxLevel: 3,\r\n      markdown: {\r\n        smartypants: true\r\n      },\r\n\r\n      remoteMarkdown: {\r\n        tag: 'remoteMarkdownUrl',\r\n      },\r\n    }\r\n  </script>\r\n  <script src=\"//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js\"></script>\r\n  <script src=\"//unpkg.com/docsify-remote-markdown/dist/docsify-remote-markdown.min.js\"></script>\r\n  <script src=\"//cdn.jsdelivr.net/npm/prismjs@1/components/prism-js-extras.min.js\"></script>\r\n  <script src=\"//cdn.jsdelivr.net/npm/prismjs@1/components/prism-js-templates.min.js\"></script>\r\n  <script src=\"//cdn.jsdelivr.net/npm/prismjs@1/components/prism-jsdoc.min.js\"></script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "index.js",
    "content": "'use strict';\nconst kebabCase = require('kebab-case');\nconst rules = require('./lib/rules/rules.json')\n\nmodule.exports.rules = require('./lib/rules/all');\n\nconst all = Object.keys(rules);\nconst compatible = Object.keys(rules).filter(rule => rules[rule].compatible);\nconst incompatible = Object.keys(rules).filter(rule => !rules[rule].compatible);\n\nconst WARN = 1;\nconst ERROR = 2;\n\nconst configure = (list, level) => (\n  list.reduce((ret, rule) => (Object.assign({}, ret,\n    { ['you-dont-need-lodash-underscore/' + (rules[rule].ruleName || kebabCase(rule))]: level })), {})\n)\n\nmodule.exports.configs = {\n  'all-warn': {\n    plugins: [\n      'you-dont-need-lodash-underscore'\n    ],\n    rules: configure(all, WARN)\n  },\n\n  'all': {\n    plugins: [\n      'you-dont-need-lodash-underscore'\n    ],\n    rules: configure(all, ERROR)\n  },\n\n  'compatible-warn': {\n    plugins: [\n      'you-dont-need-lodash-underscore'\n    ],\n    rules: configure(compatible, WARN)\n  },\n\n  'compatible': {\n    plugins: [\n      'you-dont-need-lodash-underscore'\n    ],\n    rules: Object.assign(\n      configure(compatible, ERROR),\n      configure(incompatible, WARN)\n    )\n  }\n}\n"
  },
  {
    "path": "lib/rules/all.js",
    "content": "'use strict';\nconst kebabCase = require('kebab-case');\nconst rules = require('./rules');\n\nconst forbiddenLibs = ['lodash', 'lodash/fp', 'lodash-es'];\n\nfunction getAssignmentLeftHandSide(node) {\n  // For VariableDeclarator nodes, the left hand side is called `id`\n  // The `x` on `var x = 3;\n  if (node.type === 'VariableDeclarator') {\n    return node.id;\n  }\n  // For AssignmentExpression nodes, the left hand side is called `left`\n  // The `x` on `x = 3;\n  if (node.type === 'AssignmentExpression') {\n    return node.left;\n  }\n  return null;\n}\n\nfor (const rule in rules) {\n  const alternative = rules[rule].alternative;\n  const ruleName = rules[rule].ruleName || kebabCase(rule);\n  const forbiddenImports = {\n    [`lodash/${rule}`]: 1,\n    [`lodash/fp/${rule}`]: 1,\n    [`lodash-es/${rule}`]: 1,\n    [`lodash.${rule.toLowerCase()}`]: 1,\n  };\n\n  module.exports[ruleName] = {\n    create(context) {\n      return {\n        CallExpression(node) {\n          const callee = node.callee;\n          const objectName = callee.name || (callee.object && callee.object.name) || (callee.object && callee.object.callee && callee.object.callee.name);\n\n          if (objectName === 'require' && node.arguments.length === 1) {\n            const requiredModuleName = node.arguments[0].value;\n            const { parent } = node;\n            if (forbiddenLibs.includes(requiredModuleName)) {\n              const leftHandSide = getAssignmentLeftHandSide(parent);\n              // ex: const { indexOf } = require('lodash');\n              // ex: ({ indexOf } = require('lodash'));\n              if (leftHandSide && leftHandSide.type === 'ObjectPattern') {\n                leftHandSide.properties.forEach(property => {\n                  if (property.key.name === rule) {\n                    context.report({\n                      node,\n                      message: `{ ${rule} } = require('${requiredModuleName}') detected. Consider using the native ${alternative}`\n                    });\n                  }\n                });\n              }\n            } else if (forbiddenImports.hasOwnProperty(requiredModuleName)) {\n              // ex: const indexOf = require('lodash.indexof');\n              // ex: const indexOf = require('lodash/indexOf');\n              context.report({\n                node,\n                message: `require('${requiredModuleName}') detected. Consider using the native ${alternative}`\n              });\n            }\n          } else if ((objectName === '_' || objectName === 'lodash' || objectName === 'underscore') && callee.property && callee.property.name === rule) {\n            context.report({\n              node,\n              message: `Consider using the native ${alternative}`\n            });\n          }\n        },\n        ImportDeclaration(node) {\n          if (forbiddenLibs.includes(node.source.value)) {\n            // ex: import { indexOf } from 'lodash';\n            // ex: import { indexOf as x } from 'lodash';\n            node.specifiers.forEach(specifier => {\n              if (specifier.type === 'ImportSpecifier' && specifier.imported.name === rule) {\n                context.report({\n                  node,\n                  message: `Import { ${rule} } from '${node.source.value}' detected. Consider using the native ${alternative}`\n                });\n              }\n            });\n          } else if (forbiddenImports.hasOwnProperty(node.source.value)) {\n            // ex: import indexOf from 'lodash/indexOf';\n            // ex: import indexOf from 'lodash.indexof';\n            context.report({\n              node,\n              message: `Import from '${node.source.value}' detected. Consider using the native ${alternative}`\n            });\n          }\n        }\n      };\n    }\n  };\n}\n"
  },
  {
    "path": "lib/rules/rules.json",
    "content": "{\n    \"concat\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.concat()\"\n    },\n    \"drop\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.slice()\"\n    },\n    \"dropRight\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.slice()\"\n    },\n    \"indexOf\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.indexOf()\"\n    },\n    \"join\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.join()\"\n    },\n    \"last\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.at(-1) or Array.prototype.slice()\",\n        \"ES13\": true\n    },\n    \"lastIndexOf\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.lastIndexOf()\"\n    },\n    \"reverse\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.reverse()\"\n    },\n    \"fill\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.fill()\",\n        \"ES6\": true\n    },\n    \"find\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.find()\",\n        \"ES6\": true\n    },\n    \"detect\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.find()\",\n        \"ES6\": true\n    },\n    \"first\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.at(0) or Array.prototype.slice()\",\n        \"ES13\": true\n    },\n    \"findIndex\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.findIndex()\",\n        \"ES6\": true\n    },\n    \"isArray\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.isArray()\"\n    },\n    \"each\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.forEach() or Object.entries().forEach()\"\n    },\n    \"forEach\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.forEach() or Object.entries().forEach()\"\n    },\n    \"every\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.every()\"\n    },\n    \"all\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.every()\"\n    },\n    \"filter\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.filter()\"\n    },\n    \"select\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.filter()\"\n    },\n    \"map\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.map()\"\n    },\n    \"collect\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.map()\"\n    },\n    \"reduce\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.reduce()\"\n    },\n    \"inject\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.reduce()\"\n    },\n    \"foldl\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.reduce()\"\n    },\n    \"reduceRight\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.reduceRight()\"\n    },\n    \"foldr\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.reduceRight()\"\n    },\n    \"size\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.length\"\n    },\n    \"some\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.some()\"\n    },\n    \"any\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.some()\"\n    },\n    \"includes\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.includes()\",\n        \"ES6\": true\n    },\n    \"contains\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.includes()\",\n        \"ES6\": true\n    },\n    \"slice\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.slice()\"\n    },\n    \"takeRight\": {\n        \"compatible\": false,\n        \"alternative\": \"Array.prototype.slice()\"\n    },\n    \"bind\": {\n        \"ruleName\": \"bind\",\n        \"compatible\": true,\n        \"alternative\": \"Function.prototype.bind()\"\n    },\n    \"isFinite\": {\n        \"compatible\": true,\n        \"alternative\": \"Number.isFinite()\"\n    },\n    \"isInteger\": {\n        \"ruleName\": \"is-integer\",\n        \"compatible\": true,\n        \"alternative\": \"Number.isInteger()\",\n        \"ES6\": true\n    },\n    \"isNaN\": {\n        \"ruleName\": \"is-nan\",\n        \"compatible\": true,\n        \"alternative\": \"Number.isNaN()\",\n        \"ES6\": true\n    },\n    \"isNil\": {\n        \"ruleName\": \"is-nil\",\n        \"compatible\": true,\n        \"alternative\": \"value === null || value === undefined\"\n    },\n    \"isNull\": {\n        \"ruleName\": \"is-null\",\n        \"compatible\": true,\n        \"alternative\": \"value === null\"\n    },\n    \"isUndefined\": {\n        \"ruleName\": \"is-undefined\",\n        \"compatible\": true,\n        \"alternative\": \"value === undefined\"\n    },\n    \"keys\": {\n        \"compatible\": true,\n        \"alternative\": \"Object.keys()\"\n    },\n    \"extendOwn\": {\n        \"compatible\": true,\n        \"alternative\": \"Object.assign()\",\n        \"ES6\": true\n    },\n    \"assign\": {\n        \"compatible\": true,\n        \"alternative\": \"Object.assign()\",\n        \"ES6\": true\n    },\n    \"values\": {\n        \"compatible\": true,\n        \"alternative\": \"Object.values()\",\n        \"ES6\": true\n    },\n    \"entries\": {\n        \"compatible\": true,\n        \"alternative\": \"Object.entries()\",\n        \"ES6\": true\n    },\n    \"toPairs\": {\n        \"compatible\": true,\n        \"alternative\": \"Object.entries()\",\n        \"ES6\": true\n    },\n    \"pairs\": {\n        \"compatible\": true,\n        \"alternative\": \"Object.entries()\",\n        \"ES6\": true\n    },\n    \"get\": {\n        \"compatible\": false,\n        \"alternative\": \"optional chaining to get nested values and nullish coalescing operator for fallback values\",\n        \"ES11\": true\n    },\n    \"split\": {\n        \"compatible\": true,\n        \"alternative\": \"String.prototype.split()\"\n    },\n    \"startsWith\": {\n        \"ruleName\": \"starts-with\",\n        \"compatible\": true,\n        \"alternative\": \"String.prototype.startsWith()\"\n    },\n    \"endsWith\": {\n        \"ruleName\": \"ends-with\",\n        \"compatible\": true,\n        \"alternative\": \"String.prototype.endsWith()\"\n    },\n    \"toLower\": {\n        \"compatible\": true,\n        \"alternative\": \"String.prototype.toLowerCase()\"\n    },\n    \"toUpper\": {\n        \"compatible\": true,\n        \"alternative\": \"String.prototype.toUpperCase()\"\n    },\n    \"trim\": {\n        \"compatible\": true,\n        \"alternative\": \"String.prototype.trim()\"\n    },\n    \"padStart\": {\n        \"compatible\": true,\n        \"alternative\": \"String.prototype.padStart()\",\n        \"ES6\": true\n    },\n    \"padEnd\": {\n        \"compatible\": true,\n        \"alternative\": \"String.prototype.padEnd()\",\n        \"ES6\": true\n    },\n    \"repeat\": {\n        \"compatible\": true,\n        \"alternative\": \"String.prototype.repeat()\",\n        \"ES6\": true\n    },\n    \"uniq\": {\n        \"compatible\": true,\n        \"alternative\": \"[... new Set(arr)]\",\n        \"ES6\": true\n    },\n    \"replace\": {\n        \"compatible\": true,\n        \"alternative\": \"String.prototype.replace()\"\n    },\n    \"omit\": {\n        \"compatible\": true,\n        \"alternative\": \"{a, b, c, ...notOmittedValues}\",\n        \"ES6\": true\n    },\n    \"flatten\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.reduce((a,b) => a.concat(b), [])\"\n    },\n    \"throttle\": {\n        \"compatible\": true,\n        \"alternative\": \"Example of native implementation: https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_throttle\"\n    },\n    \"isString\": {\n        \"compatible\": true,\n        \"alternative\": \"str != null && typeof str.valueOf() === \\\"string\\\"\"\n    },\n    \"castArray\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.isArray(arr) ? arr : [arr]\"\n    },\n    \"cloneDeep\": {\n        \"compatible\": true,\n        \"alternative\": \"structuredClone()\"\n    },\n    \"isFunction\": {\n        \"compatible\": true,\n        \"alternative\": \"typeof func === \\\"function\\\"\"\n    },\n    \"unionBy\": {\n        \"compatible\": false,\n        \"alternative\": \"Example of native implementation: https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_unionBy\",\n        \"ES10\": true\n    },\n    \"capitalize\": {\n        \"compatible\": true,\n        \"alternative\": \"string.charAt(0).toUpperCase() + string.slice(1).toLowerCase()\"\n    },\n    \"isDate\": {\n        \"compatible\": true,\n        \"alternative\": \"String.prototype.toString.call()\"\n    },\n    \"defaults\": {\n        \"compatible\": true,\n        \"alternative\": \"Object.assign({}, defaultValues, newValues)\",\n        \"ES6\": true\n    },\n    \"isArrayBuffer\": {\n        \"compatible\": false,\n        \"alternative\": \"value instanceof ArrayBuffer\"\n    },\n    \"head\": {\n        \"compatible\": true,\n        \"alternative\": \"Array.prototype.at(0)\",\n        \"ES13\": true\n    }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"eslint-plugin-you-dont-need-lodash-underscore\",\n  \"version\": \"6.14.0\",\n  \"description\": \"Check methods you can use natively without lodash/underscore\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore.git\"\n  },\n  \"keywords\": [\n    \"underscore\",\n    \"lodash\",\n    \"eslint\",\n    \"eslintplugin\",\n    \"eslint-plugin\",\n    \"native\"\n  ],\n  \"author\": \"Robert Chang <cht8687@gmail.com>\",\n  \"contributors\": [\n    \"Patrick McElhaney <pmcelhaney@gmail.com> (http://patrickmcelhaney.com)\",\n    \"Steve Mao <maochenyan@gmail.com> (https://github.com/stevemao)\"\n  ],\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"coveralls\": \"cat ./coverage/lcov.info | coveralls\",\n    \"test\": \"istanbul cover tests\",\n    \"test:unit\": \"mocha tests/unit\"\n  },\n  \"dependencies\": {\n    \"kebab-case\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"coveralls\": \"^3.1.1\",\n    \"eslint\": \"^8.48.0\",\n    \"istanbul\": \"^0.4.4\",\n    \"lodash\": \"^4.17.4\",\n    \"mocha\": \"^10.2.0\"\n  },\n  \"engines\": {\n    \"node\": \">=4.0\"\n  },\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore/issues\"\n  },\n  \"homepage\": \"https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore.git\"\n}\n"
  },
  {
    "path": "tests/index.js",
    "content": "require('./lib/rules/all.js');\n\nconst assert = require('assert');\nconst plugin = require('../');\n\nassert.equal(plugin.configs['all-warn'].rules['you-dont-need-lodash-underscore/contains'], 1);\nassert.equal(plugin.configs['all-warn'].rules['you-dont-need-lodash-underscore/trim'], 1);\nassert.equal(plugin.configs.all.rules['you-dont-need-lodash-underscore/every'], 2);\nassert.equal(plugin.configs.all.rules['you-dont-need-lodash-underscore/keys'], 2);\nassert.equal(plugin.configs['compatible-warn'].rules['you-dont-need-lodash-underscore/each'], undefined);\nassert.equal(plugin.configs['compatible-warn'].rules['you-dont-need-lodash-underscore/last-index-of'], 1);\nassert.equal(plugin.configs.compatible.rules['you-dont-need-lodash-underscore/for-each'], 1);\nassert.equal(plugin.configs.compatible.rules['you-dont-need-lodash-underscore/is-nan'], 2);\n"
  },
  {
    "path": "tests/lib/rules/all.js",
    "content": "'use strict';\nconst RuleTester = require('eslint').RuleTester;\nconst assert = require('assert');\nconst rules = require('../../../lib/rules/all');\nconst allRules = require('../../../lib/rules/rules');\n\nconst ruleTester = new RuleTester({\n  parserOptions: { ecmaVersion: 2018, sourceType: \"module\" }\n});\n\n// Only a couple of smoke tests because otherwise it would get very redundant\n\nruleTester.run('_.concat', rules.concat, {\n  valid: [\n    'array.concat(2, [3], [[4]])'\n  ],\n  invalid: [{\n    code: '_.concat(array, 2, [3], [[4]])',\n    errors: ['Consider using the native Array.prototype.concat()']\n  }]\n});\n\nruleTester.run('lodash.keys', rules.keys, {\n  valid: [\n    'Object.keys({one: 1, two: 2, three: 3})'\n  ],\n  invalid: [{\n    code: 'lodash.keys({one: 1, two: 2, three: 3})',\n    errors: ['Consider using the native Object.keys()']\n  }]\n});\n\nruleTester.run(`Import lodash.isnan`, rules['is-nan'], {\n  valid: [`{ x: require('lodash') }`],\n  invalid: [{\n    code: `import isNaN from 'lodash/isNaN';`,\n    errors: [`Import from 'lodash/isNaN' detected. Consider using the native Number.isNaN()`]\n  }, {\n    code: `import isNaN from 'lodash.isnan';`,\n    errors: [`Import from 'lodash.isnan' detected. Consider using the native Number.isNaN()`]\n  }, {\n    code: `import { isNaN as x } from 'lodash';`,\n    errors: [`Import { isNaN } from 'lodash' detected. Consider using the native Number.isNaN()`]\n  }, {\n    code: `const { isNaN: x } = require('lodash');`,\n    errors: [`{ isNaN } = require('lodash') detected. Consider using the native Number.isNaN()`]\n  }, {\n    code: `({ isNaN: x } = require('lodash'));`,\n    errors: [`{ isNaN } = require('lodash') detected. Consider using the native Number.isNaN()`]\n  }, {\n    code: `require('lodash/isNaN');`,\n    errors: [`require('lodash/isNaN') detected. Consider using the native Number.isNaN()`]\n  }, {\n    code: `require('lodash.isnan');`,\n    errors: [`require('lodash.isnan') detected. Consider using the native Number.isNaN()`]\n  }]\n});\n\nruleTester.run(`Import { isNaN } from lodash-es`, rules['is-nan'], {\n  valid: [`{ x: require('lodash-es') }`],\n  invalid: [{\n    code: `import { isNaN } from 'lodash-es';`,\n    errors: [`Import { isNaN } from 'lodash-es' detected. Consider using the native Number.isNaN()`]\n  },\n    {\n    code: `import isNaN from 'lodash-es/isNaN';`,\n    errors: [`Import from 'lodash-es/isNaN' detected. Consider using the native Number.isNaN()`]\n  }, {\n    code: `import { isNaN as x } from 'lodash-es';`,\n    errors: [`Import { isNaN } from 'lodash-es' detected. Consider using the native Number.isNaN()`]\n  }, {\n    code: `const { isNaN: x } = require('lodash-es');`,\n    errors: [`{ isNaN } = require('lodash-es') detected. Consider using the native Number.isNaN()`]\n  }, {\n    code: `({ isNaN: x } = require('lodash-es'));`,\n    errors: [`{ isNaN } = require('lodash-es') detected. Consider using the native Number.isNaN()`]\n  }, {\n    code: `require('lodash-es/isNaN');`,\n    errors: [`require('lodash-es/isNaN') detected. Consider using the native Number.isNaN()`]\n  }]\n});\n\nruleTester.run('underscore.forEach', rules['for-each'], {\n  valid: [\n    '[0, 1].forEach()',\n    \"Object.entries({'one':1,'two':2}).forEach()\"\n  ],\n  invalid: [{\n    code: 'underscore.forEach()',\n    errors: ['Consider using the native Array.prototype.forEach() or Object.entries().forEach()']\n  }]\n});\n\nruleTester.run('underscore.isNaN', rules['is-nan'], {\n  valid: [\n    'Number.isNaN(NaN);'\n  ],\n  invalid: [{\n    code: 'underscore.isNaN(NaN)',\n    errors: ['Consider using the native Number.isNaN()']\n  }]\n});\n\nruleTester.run('_.first', rules['first'], {\n  valid: [\n    '[0, 1, 3][0]',\n    '[0, 1, 3].at(0)',\n    '[0, 1, 3].slice(0, 2)'\n  ],\n  invalid: [{\n      code: '_.first([0, 1, 3])',\n      errors: ['Consider using the native Array.prototype.at(0) or Array.prototype.slice()']\n  }, {\n    code: '_.first([0, 1, 3], 2)',\n    errors: ['Consider using the native Array.prototype.at(0) or Array.prototype.slice()']\n  }]\n});\n\nruleTester.run('_.last', rules['last'], {\n  valid: [\n    'var numbers = [0, 1, 3]; numbers[numbers.length - 1]',\n    '[0, 1, 3].at(-1)',\n    '[0, 1, 3].slice(-2)'\n  ],\n  invalid: [{\n      code: '_.last([0, 1, 3])',\n      errors: ['Consider using the native Array.prototype.at(-1) or Array.prototype.slice()']\n  }, {\n    code: '_.last([0, 1, 3], 2)',\n    errors: ['Consider using the native Array.prototype.at(-1) or Array.prototype.slice()']\n  }]\n});\n\nruleTester.run('_', rules.concat, {\n  valid: [\n    '_(2, [3], [[4]])'\n  ],\n  invalid: []\n});\n\nruleTester.run('_.isUndefined', rules['is-undefined'], {\n  valid: [\n    '2 === undefined'\n  ],\n  invalid: [{\n    code: '_.isUndefined(2)',\n    errors: ['Consider using the native value === undefined']\n  },{\n    code: '_(2).isUndefined()',\n    errors: ['Consider using the native value === undefined']\n\n  }]\n});\n\n/*This is to make sure that You-Dont-Need-Lodash can handle the\nevaluation of nested functions that had caused an error noted in the comments of\nPull Request #219*/\nruleTester.run('Nested functions', rules['is-undefined'], {\n  valid: [\n    `function myNestedFunction(firstInput) {\n      return (secondInput) => {\n        return firstInput + secondInput\n      }\n    }\n    myNestedFunction(2)(2)`\n  ],\n  invalid: []\n});\n\n/*Test for new flatten rule*/\nruleTester.run('_.flatten', rules['flatten'], {\n  valid: [\n    `[1,2,[3,4]].reduce((a,b) => a.concat(b), [])`,\n    `[1,2,[3,4]].flat()`,\n    `[1,2,[3,4]].flatMap(a => a)`\n  ],\n  invalid: [{\n    code: `_.flatten([1,2,[3,4]])`,\n    errors: [`Consider using the native Array.prototype.reduce((a,b) => a.concat(b), [])`]\n  },{\n    code: `_([1,2,[3,4]]).flatten()`,\n    errors: [`Consider using the native Array.prototype.reduce((a,b) => a.concat(b), [])`]\n  }]\n});\n\nruleTester.run('_.isUndefined', rules['is-undefined'], {\n  valid: [\n    '2 === undefined'\n  ],\n  invalid: [{\n    code: '_.isUndefined(2)',\n    errors: ['Consider using the native value === undefined']\n  },{\n    code: '_(2).isUndefined()',\n    errors: ['Consider using the native value === undefined']\n\n  }]\n});\n\nruleTester.run('_.startsWith', rules['starts-with'], {\n  valid: [\n    '\"abc\".startsWith(\"a\")',\n    '\"abc\".startsWith(\"b\", 1)'\n  ],\n  invalid: [{\n    code: '_.startsWith(\"abc\", \"a\")',\n    errors: ['Consider using the native String.prototype.startsWith()']\n  },{\n    code: '_.startsWith(\"abc\", \"b\", 1)',\n    errors: ['Consider using the native String.prototype.startsWith()']\n\n  }]\n});\n\nruleTester.run('_.endsWith', rules['ends-with'], {\n  valid: [\n    '\"abc\".endsWith(\"c\")',\n    '\"abc\".endsWith(\"b\", 1)'\n  ],\n  invalid: [{\n    code: '_.endsWith(\"abc\", \"c\")',\n    errors: ['Consider using the native String.prototype.endsWith()']\n  },{\n    code: '_.endsWith(\"abc\", \"b\", 1)',\n    errors: ['Consider using the native String.prototype.endsWith()']\n\n  }]\n});\n\nruleTester.run('_.head', rules['head'], {\n  valid: [\n    '[0, 1, 3].at(0)',\n  ],\n  invalid: [{\n      code: '_.head([0, 1, 3])',\n      errors: ['Consider using the native Array.prototype.at(0)']\n  }]\n});\n\n"
  },
  {
    "path": "tests/unit/all.js",
    "content": "'use strict';\nconst assert = require('assert');\nconst _ = require('lodash');\n\ndescribe('code snippet example', () => {\n\n  it('compact', () => {\n    assert.deepEqual(\n      _.compact([0, 1, false, 2, '', 3]),\n      [0, 1, false, 2, '', 3].filter(v => v)\n    )\n  })\n\n  it('concat', () => {\n    const lodashArray = [1]\n    const lodashResult = _.concat(lodashArray, 2, [3], [[4]])\n\n    const nativeArray = [1]\n    const nativeResult = nativeArray.concat(2, [3], [[4]])\n\n    assert.deepEqual(lodashResult, nativeResult)\n  })\n\n  it('invert', () => {\n    var object = { 'a': 1, 'b': '2', 'c': 3 };\n    function invert(object) {\n      var obj = {};\n      for (var key in object) {\n        if (object.hasOwnProperty(key)) {\n          obj[object[key]] = key;\n        }\n      }\n      return obj;\n    }\n    assert.deepEqual(\n      _.invert(object),\n      invert(object)\n    )\n  })\n  \n  it('mapKeys', () => {\n    var object = { 'a': 1, 'b': 2 };\n    function mapKeys(object, cb) {\n      var obj = {};\n      for (var key in object) {\n        if (object.hasOwnProperty(key)) {\n          var newKey = cb(object[key], key, object);\n          obj[newKey] = object[key];\n        }\n      }\n      return obj;\n    }\n    assert.deepEqual(\n      _.mapKeys(object, function (value, key) {\n        return key + value;\n      }),\n      mapKeys(object, function (value, key) {\n        return key + value;\n      })\n    )\n  })\n\n  it('pick', () => {\n    var object = { 'a': 1, 'b': '2', 'c': 3 };\n    function pick(object, keys) {\n      return keys.reduce((obj, key) => {\n        if (object && object.hasOwnProperty(key)) {\n          obj[key] = object[key];\n        }\n        return obj;\n      }, {});\n    }\n    assert.deepEqual(\n      _.pick(object, ['a', 'c', 'x']),\n      pick(object, ['a', 'c', 'x'])\n    )\n  })\n  \n  it('pickBy', () => {\n    var object = { 'a': 1, 'b': null, 'c': 3, 'd': false, 'e': undefined, 'f': '', 'g': 0 };\n    function pickBy(object) {\n      const obj = {};\n      for (const key in object) {\n        if (object[key]) {\n          obj[key] = object[key];\n        }\n      }\n      return obj;\n    }\n    assert.deepEqual(\n      _.pickBy(object),\n      pickBy(object)\n    )\n  })\n\n  describe('fill', () => {\n    it(\"_.fill(array, 'a')\", () => {\n      var array = [1, 2, 3]\n      assert.deepEqual(\n        _.fill(array, 'a'),\n        array.fill('a')\n      )\n    })\n    it(\"_.fill(Array(3), 2)\", () => {\n      assert.deepEqual(\n        _.fill(Array(3), 2),\n        Array(3).fill(2)\n      )\n    })\n\n    it(\"_.fill([4, 6, 8, 10], '*', 1, 3)\", () => {\n      assert.deepEqual(\n        _.fill([4, 6, 8, 10], '*', 1, 3),\n        [4, 6, 8, 10].fill('*', 1, 3)\n      )\n    })\n  })\n  describe('chunk', () => {\n    const chunk = (input, size) => {\n      return input.reduce((arr, item, idx) => {\n        return idx % size === 0\n          ? [...arr, [item]]\n          : [...arr.slice(0, -1), [...arr.slice(-1)[0], item]];\n      }, []);\n    };\n    it(\"_.chunk(['a', 'b', 'c', 'd'], 2);\", () => {\n      assert.deepEqual(\n        _.chunk(['a', 'b', 'c', 'd'], 2),\n        chunk(['a', 'b', 'c', 'd'], 2)\n      )\n    })\n    it(\"_.chunk(['a', 'b', 'c', 'd'], 3);\", () => {\n      assert.deepEqual(\n        _.chunk(['a', 'b', 'c', 'd'], 3),\n        chunk(['a', 'b', 'c', 'd'], 3)\n      )\n    })\n  })\n  describe('times', () => {\n    const times = (n, fn = (_, x) => x) => {\n      return Array.from(Array(n), fn)\n    };\n    it(\"_.times(10);\", () => {\n      assert.deepEqual(\n        _.times(10),\n        times(10)\n      )\n    })\n    it(\"_.times(10, x => x + 1);\", () => {\n      assert.deepEqual(\n        _.times(10, x => x + 1),\n        times(10, (_, x) => x + 1)\n      )\n    })\n  })\n\n  describe('assign', () => {\n    function Foo() {\n      this.c = 3;\n    }\n    function Bar() {\n      this.e = 5;\n    }\n    Foo.prototype.d = 4;\n    Bar.prototype.f = 6;\n    const assign = (target, ...sources) => Object.assign(target, ...sources);\n    it(\"_.assign({}, new Foo, new Bar);\", () => {\n      assert.deepEqual(\n        _.assign({}, new Foo, new Bar),\n        assign({}, new Foo, new Bar)\n      )\n    })\n    it(\"_.assign(new Foo, new Bar);\", () => {\n      assert.deepEqual(\n        _.assign(new Foo, new Bar),\n        assign(new Foo, new Bar)\n      )\n    })\n  })\n  describe('extend', () => {\n    function Foo() {\n      this.c = 3;\n    }\n    function Bar() {\n      this.e = 5;\n    }\n    Foo.prototype.d = 4;\n    Bar.prototype.f = 6;\n\n    const extend = (target, ...sources) => {\n      const length = sources.length;\n\n      if (length < 1 || target == null) return target;\n      for (let i = 0; i < length; i++) {\n        const source = sources[i];\n\n        for (const key in source) {\n          target[key] = source[key];\n        }\n      }\n      return target;\n    };\n\n    it(\"_.extend({}, new Foo, new Bar);\", () => {\n      assert.deepEqual(\n        _.extend({}, new Foo, new Bar),\n        extend({}, new Foo, new Bar)\n      )\n    })\n    it(\"_.extend(new Foo, new Bar);\", () => {\n      assert.deepEqual(\n        _.extend(new Foo, new Bar),\n        extend(new Foo, new Bar)\n      )\n    })\n  })\n  describe('isDate', () => {\n    const isDate = (obj) => {\n      return (obj ? Object.prototype.toString.call(obj) === \"[object Date]\" : false);\n    };\n    it ('_.Date(null)', () => {\n      assert.equal(\n        _.isDate(null),\n        isDate(null)\n      )\n    })\n    it (\"_.Date('Mon April 23 2012')\", () => {\n      assert.equal(\n        _.isDate('Mon April 23 2012'),\n        isDate('Mon April 23 2012')\n      )\n    })\n    it ('_.Date(new Date)', () => {\n      assert.equal(\n        _.isDate(new Date),\n        isDate(new Date)\n      )\n    })\n  })\n  describe('isEmpty', () => {\n    const isEmpty = (obj) => {\n      return (obj ? [Object, Array].includes(obj.constructor) && !Object.entries(obj).length : true);\n    };\n    it ('_.isEmpty(null)', () => {\n      assert.equal(\n        _.isEmpty(null),\n        isEmpty(null)\n      )\n    })\n    it (\"_.isEmpty('')\", () => {\n      assert.equal(\n        _.isEmpty(''),\n        isEmpty('')\n      )\n    })\n    it (\"_.isEmpty({})\", () => {\n      assert.equal(\n        _.isEmpty({}),\n        isEmpty({})\n      )\n    })\n    it (\"_.isEmpty([])\", () => {\n      assert.equal(\n        _.isEmpty([]),\n        isEmpty([])\n      )\n    })\n    it (\"_.isEmpty({a: '1'})\", () => {\n      assert.equal(\n        _.isEmpty({a: '1'}),\n        isEmpty({a: '1'})\n      )\n    })\n  })\n  describe('isInteger', () => {\n    it('_.isInteger(3)', () => {\n       assert.equal(\n        _.isInteger(3),\n        Number.isInteger(3)\n      )\n    })\n    it('_.isInteger(\"3\")', () => {\n       assert.equal(\n        _.isInteger(\"3\"),\n        Number.isInteger(\"3\")\n       )\n    })\n    it('_.isInteger(2.9)', () => {\n       assert.equal(\n        _.isInteger(2.9),\n        Number.isInteger(2.9)\n       )\n    })\n    it('_.isInteger(NaN)', () => {\n       assert.equal(\n        _.isInteger(NaN),\n        Number.isInteger(NaN)\n       )\n    })\n  })\n  describe('isPlainObject', () => {\n    function isPlainObject(value) {\n      if (typeof value !== 'object' || value === null) return false\n  \n      if (Object.prototype.toString.call(value) !== '[object Object]') return false\n  \n      const proto = Object.getPrototypeOf(value);\n      if (proto === null) return true\n  \n      const Ctor = Object.prototype.hasOwnProperty.call(proto, 'constructor') && proto.constructor;\n      return (\n          typeof Ctor === 'function' &&\n          Ctor instanceof Ctor && Function.prototype.call(Ctor) === Function.prototype.call(value)\n      );\n    }\n\n    function Foo() {\n      this.a = 1;\n    }\n\n    it('_.isPlainObject(NaN)', () => {\n      assert.equal(\n      _.isPlainObject(NaN),\n      isPlainObject(NaN)\n      )\n    })\n    it('_.isPlainObject([1, 2, 3])', () => {\n      assert.equal(\n      _.isPlainObject([1, 2, 3]),\n      isPlainObject([1, 2, 3])\n      )\n    })\n    it('_.isPlainObject(null)', () => {\n      assert.equal(\n      _.isPlainObject(null),\n      isPlainObject(null)\n      )\n    })\n    it(\"_.isPlainObject({ 'x': 0, 'y': 0 })\", () => {\n      assert.equal(\n      _.isPlainObject({ 'x': 0, 'y': 0 }),\n      isPlainObject({ 'x': 0, 'y': 0 })\n      )\n    })\n    it(\"_.isPlainObject(Object.create(null))\", () => {\n      assert.equal(\n      _.isPlainObject(Object.create(null)),\n      isPlainObject(Object.create(null))\n      )\n    })\n    it(\"_.isPlainObject(Object.create(new Foo()))\", () => {\n      assert.equal(\n      _.isPlainObject(Object.create(new Foo())),\n      isPlainObject(Object.create(new Foo()))\n      )\n    })\n    it(\"_.isPlainObject(Object.create(new Date()))\", () => {\n      assert.equal(\n      _.isPlainObject(Object.create(new Date())),\n      isPlainObject(Object.create(new Date()))\n      )\n    })\n  })\n  describe('get', () => {\n    const get = (obj, path, defaultValue) => {\n      const travel = regexp =>\n        String.prototype.split\n          .call(path, regexp)\n          .filter(Boolean)\n          .reduce((res, key) => (res !== null && res !== undefined ? res[key] : res), obj);\n      const result = travel(/[,[\\]]+?/) || travel(/[,[\\].]+?/);\n      return result === undefined || result === obj ? defaultValue : result;\n    };\n    var obj = {\n      aa: [{ b: { c: 0 }, 1: 0 }],\n      dd: { ee: { ff: 2 } },\n      gg: { h: 2 },\n      \"gg.h\": 1,\n      \"kk.ll\": { \"mm.n\": [3, 4, { \"oo.p\": 5 }] }\n    };\n\n    it (\"should handle falsy values\", () => {\n      var val = _.get(obj, 'aa[0].b.c', 1)\n      assert.strictEqual(val, get(obj, 'aa[0].b.c', 1))\n      assert.notEqual(val, 1)\n    })\n    it (\"should handle just bracket notation\", () => {\n      var val = _.get(obj, 'aa[0][1]', 1)\n      assert.strictEqual(val, get(obj, 'aa[0][1]', 1))\n      assert.notEqual(val, 1)\n    })\n    it (\"should handle just period notation\", () => {\n      var val = _.get(obj, 'dd.ee.ff', 1)\n      assert.strictEqual(val, get(obj, 'dd.ee.ff', 1))\n      assert.notEqual(val, 1)\n    })\n    it (\"should handle neither notation\", () => {\n      var val = _.get(obj, 'aa', 1)\n      assert.deepEqual(val, get(obj, 'aa', 1))\n      assert.notEqual(val, 1)\n    })\n    it (\"should handle both notation\", () => {\n      var val = _.get(obj, 'aa[0].b.c', 1)\n      assert.strictEqual(val, get(obj, 'aa[0].b.c', 1))\n      assert.notEqual(val, 1)\n    })\n    it (\"should handle array path\", () => {\n      var val = _.get(obj, ['aa', [0], 'b', 'c'], 1)\n      assert.strictEqual(val, get(obj, ['aa', [0], 'b', 'c'], 1))\n      assert.notEqual(val, 1)\n    })\n    it (\"should handle undefined without default\", () => {\n      var val = _.get(obj, 'dd.b')\n      assert.strictEqual(val, get(obj, 'dd.b'))\n    })\n    it (\"should handle undefined with default\", () => {\n      var val = _.get(obj, 'dd.b', 1)\n      assert.strictEqual(val, get(obj, 'dd.b', 1))\n    })\n    it (\"should handle deep undefined without default\", () => {\n      var val = _.get(obj, 'dd.b.c')\n      assert.strictEqual(val, get(obj, 'dd.b.c'))\n    })\n    it (\"should handle deep undefined with default\", () => {\n      var val = _.get(obj, 'dd.b.c', 1)\n      assert.strictEqual(val, get(obj, 'dd.b.c', 1))\n      assert.strictEqual(val, 1);\n    })\n    it (\"should handle null default\", () => {\n      var val = _.get(obj, 'dd.b', null)\n      assert.strictEqual(val, get(obj, 'dd.b', null))\n      assert.strictEqual(val, null);\n    })\n    it (\"should handle empty path\", () => {\n      var val = _.get(obj, '', 1)\n      assert.strictEqual(val, get(obj, '', 1))\n      assert.notEqual(val, obj);\n    })\n    it (\"should handle undefined obj\", () => {\n      var val = _.get(undefined, 'aa')\n      assert.strictEqual(val, get(undefined, 'aa'))\n    })\n    it (\"should handle path contains a key with dots\", () => {\n      var val = _.get(obj, 'gg.h')\n      assert.strictEqual(val, get(obj, 'gg.h'))\n      assert.strictEqual(val, 1)\n    })\n    it (\"should handle array path of keys with dots\", () => {\n      var val = _.get(obj, [\"kk.ll\", \"mm.n\", 0, \"oo.p\"])\n      assert.strictEqual(\n        val,\n        get(obj, [\"kk.ll\", \"mm.n\", 0, \"oo.p\"])\n      );\n    })\n  })\n  describe('split', () => {\n    const source = 'a-b-c';\n    const separator = '-';\n    const limit = 2;\n    it(`_.split(\"${source}\", \"${separator}\")`, () => {\n      assert.deepEqual(\n        _.split(source, separator),\n        source.split(separator)\n      );\n    })\n    it(`_.split(\"${source}\", \"${separator}\", ${limit})`, () => {\n      assert.deepEqual(\n        _.split(source, separator, limit),\n        source.split(separator, limit)\n      );\n    })\n  })\n  describe('inRange', () => {\n    const inRange = (num, init, final) => {\n      if(final === undefined){\n        final = init;\n        init = 0;\n      }\n      return (num >= Math.min(init, final) && num < Math.max(init, final));\n    }\n\n    it('_.inRange(3, 2, 4)', () => {\n      assert.equal(\n        _.inRange(3, 2, 4),\n        inRange(3, 2, 4)\n      )\n    });\n\n    it('_.inRange(4, 8)', () => {\n      assert.equal(\n        _.inRange(4, 8),\n        inRange(4, 8)\n      )\n    });\n\n    it('_.inRange(4, 2)', () => {\n      assert.equal(\n        _.inRange(4, 2),\n        inRange(4, 2)\n      )\n    });\n\n    it('_.inRange(2, 2)', () => {\n      assert.equal(\n        _.inRange(2, 2),\n        inRange(2, 2)\n      )\n    });\n\n    it('_.inRange(1.2, 2)', () => {\n      assert.equal(\n        _.inRange(1.2, 2),\n        inRange(1.2, 2)\n      )\n    });\n\n    it('_.inRange(5.2, 4)', () => {\n      assert.equal(\n        _.inRange(5.2, 4),\n        inRange(5.2, 4)\n      )\n    });\n\n    it('_.inRange(-3, -2, -6)', () => {\n      assert.equal(\n        _.inRange(-3, -2, -6),\n        inRange(-3, -2, -6)\n      )\n    });\n\n    it('_.inRange(1, 1, 5)', () => {\n      assert.equal(\n        _.inRange(1, 1, 5),\n        inRange(1, 1, 5)\n      )\n    });\n  })\n\n  describe('random', () => {\n    const random = (a = 1, b = 0) => {\n      const lower = Math.min(a, b);\n      const upper = Math.max(a, b);\n      return lower + Math.random() * (upper - lower);\n    };\n\n    const array = Array(1000).fill(0);\n\n    it('random() in range [0, 1]', () => {\n      assert.ok(array.every(() => {\n        const randomValue = random();\n        return randomValue >= 0 && randomValue <= 1;\n      }));\n    });\n\n    it('random() is float', () => {\n      assert.ok(array.some(() => {\n        const randomValue = random();\n        return !Number.isInteger(randomValue);\n      }));\n    });\n\n    it('random(5) in range [0, 5]', () => {\n      assert.ok(array.every(() => {\n        const randomValue = random(5);\n        return randomValue >= 0 && randomValue <= 5;\n      }));\n    });\n\n    it('random(5) is float', () => {\n      assert.ok(array.some(() => {\n        const randomValue = random(5);\n        return !Number.isInteger(randomValue);\n      }));\n    });\n\n    it('random(-10) supports negative', () => {\n      assert.ok(array.every(() => {\n        const randomValue = random(-10);\n        return randomValue <= 0;\n      }));\n    });\n\n    it('random(10, 5) swap the bounds', () => {\n      assert.ok(array.every(() => {\n        const randomValue = random(10, 5);\n        return randomValue >= 5 && randomValue <= 10;\n      }));\n    });\n\n    it('random(-10, 10) supports negative', () => {\n      assert.ok(array.some(() => {\n        const randomValue = random(-10, 10);\n        return randomValue > 0;\n      }));\n      assert.ok(array.some(() => {\n        const randomValue = random(-10, 10);\n        return randomValue < 0;\n      }));\n    });\n\n    it('random(-10, 10) in range [-10, 10]', () => {\n      assert.ok(array.every(() => {\n        const randomValue = random(-10, 10);\n        return randomValue >= -10 && randomValue <= 10;\n      }));\n    });\n\n    it('random(1.2, 5.2) supports floats', () => {\n      assert.ok(array.every(() => {\n        const randomValue = random(1.2, 5.2);\n        return randomValue >= 1.2 && randomValue <= 5.2;\n      }));\n    });\n\n    it('random(100000, 100001) in range [100000, 100001]', () => {\n      assert.ok(array.every(() => {\n        const randomValue = random(100000, 100001);\n        return randomValue >= 100000 && randomValue <= 100001;\n      }));\n    });\n  });\n\n  describe('randomInt', () => {\n    const randomInt = (a = 1, b = 0) => {\n      const lower = Math.ceil(Math.min(a, b));\n      const upper = Math.floor(Math.max(a, b));\n      return Math.floor(lower + Math.random() * (upper - lower + 1))\n    };\n\n    const array = Array(1000).fill(0);\n\n    const uniq = (arr) => [...new Set(arr)];\n\n    it('randomInt() return `0` or `1`', () => {\n      const randoms = uniq(array.map(() => {\n        return randomInt();\n      })).sort();\n      assert.deepStrictEqual(randoms, [0, 1]);\n    });\n\n    it('randomInt(5) in range [0, 5]', () => {\n      assert.ok(array.every(() => {\n        const randomValue = randomInt(5);\n        return randomValue >= 0 && randomValue <= 5;\n      }));\n    });\n\n    it('randomInt(5) is integer', () => {\n      assert.ok(array.some(() => {\n        const randomValue = randomInt(5);\n        return Number.isInteger(randomValue);\n      }));\n    });\n\n    it('randomInt(-10) supports negative', () => {\n      assert.ok(array.every(() => {\n        const randomValue = randomInt(-10);\n        return randomValue <= 0;\n      }));\n    });\n\n    it('randomInt(10, 5) swap the bounds', () => {\n      assert.ok(array.every(() => {\n        const randomValue = randomInt(10, 5);\n        return randomValue >= 5 && randomValue <= 10;\n      }));\n    });\n\n    it('randomInt(-10, 10) supports negative', () => {\n      assert.ok(array.some(() => {\n        const randomValue = randomInt(-10, 10);\n        return randomValue > 0;\n      }));\n      assert.ok(array.some(() => {\n        const randomValue = randomInt(-10, 10);\n        return randomValue < 0;\n      }));\n    });\n\n    it('randomInt(-10, 10) in range [-10, 10]', () => {\n      assert.ok(array.every(() => {\n        const randomValue = randomInt(-10, 10);\n        return randomValue >= -10 && randomValue <= 10;\n      }));\n    });\n\n    it('randomInt(1.2, 5.2) supports floats', () => {\n      assert.ok(array.every(() => {\n        const randomValue = randomInt(1.2, 5.2);\n        return randomValue >= 2 && randomValue <= 5;\n      }));\n    });\n\n    it('randomInt(100000, 100001) return `100000` or `100001`', () => {\n      const randoms = uniq(array.map(() => {\n        return randomInt(100000, 100001);\n      })).sort();\n      assert.deepStrictEqual(randoms, [100000, 100001]);\n    });\n  });\n\n  describe('clamp', () => {\n    const clamp = (number, boundOne, boundTwo) => {\n      if (!boundTwo) {\n        return Math.max(number, boundOne) === boundOne ? number : boundOne;\n      } else if (Math.min(number, boundOne) === number) {\n        return boundOne;\n      } else if (Math.max(number, boundTwo) === number) {\n        return boundTwo;\n      }\n      return number;\n    };\n    it('clamp(-10, -5, 5) returns lower bound if number is less than it', () => {\n      assert.deepStrictEqual(clamp(-10, -5, 5), -5);\n    });\n    it('clamp(10, -5, 5) returns upper bound if number is greater than it', () => {\n      assert.deepStrictEqual(clamp(10, -5, 5), 5);\n    });\n    it('clamp(10, -5) treats second parameter as upper bound', () => {\n      assert.deepStrictEqual(clamp(10, -5), -5);\n    });\n  });\n\n  describe('padStart', () => {\n    it('_.padStart(\"123\", 5, \"0\")', () => {\n      assert.equal(\n        _.padStart(\"123\", 5, '0'),\n        \"123\".padStart(5, '0')\n      );\n    })\n\n    it('_.padStart(\"123\", 6, \"_-\")', () => {\n      assert.equal(\n        _.padStart(\"123\", 6, '_-'),\n        \"123\".padStart(6, '_-')\n      );\n    })\n  })\n\n  describe('padEnd', () => {\n    it('_.padEnd(\"123\", 5, \"0\")', () => {\n      assert.equal(\n        _.padEnd(\"123\", 5, '0'),\n        \"123\".padEnd(5, '0')\n      );\n    })\n\n    it('_.padEnd(\"123\", 6, \"_-\")', () => {\n      assert.equal(\n        _.padEnd(\"123\", 6, '_-'),\n        \"123\".padEnd(6, '_-')\n      );\n    })\n  })\n\n  describe('upperFirst', () => {\n    const upperFirst = (string) => {\n      return string ? string.charAt(0).toUpperCase() + string.slice(1) : ''\n    }\n\n    it('_.upperFirst(\"george\")', () => {\n      assert.equal(\n        _.upperFirst('george'),\n        upperFirst('george')\n      )\n    })\n\n    it('_.upperFirst(null)', () => {\n      assert.equal(\n        _.upperFirst(null),\n        upperFirst(null)\n      )\n    })\n\n    it('_.upperFirst(\"\")', () => {\n      assert.equal(\n        _.upperFirst(''),\n        upperFirst('')\n      )\n    })\n  })\n\n\n\n  describe('isString', () => {\n    function isString(str) {\n      if (str != null && typeof str.valueOf() === \"string\") {\n        return true\n      }\n      return false\n    }\n\n    it('_.isString(\"abc\")', () => {\n      assert.deepEqual(_.isString(\"abc\"),\n        isString(\"abc\"))\n    });\n\n    it('_.isString(1)', () => {\n      assert.deepEqual(_.isString(1),\n        isString(1))\n    });\n\n    it('_.isString(\"\")', () => {\n      assert.deepEqual(_.isString(''),\n        isString(''))\n    })\n  });\n\n\n  describe('lowerFirst', () => {\n    const lowerFirst = (string) => {\n      return string ? string.charAt(0).toLowerCase() + string.slice(1) : ''\n    }\n\n    it('_.lowerFirst(\"Fred\")', () => {\n      assert.equal(\n        _.lowerFirst('fred'),\n        lowerFirst('fred')\n      )\n    })\n\n    it('_.lowerFirst(null)', () => {\n      assert.equal(\n        _.lowerFirst(null),\n        lowerFirst(null)\n      )\n    })\n\n    it('_.lowerFirst(\"\")', () => {\n      assert.equal(\n        _.lowerFirst(''),\n        lowerFirst('')\n      )\n    })\n  })\n\n\n  describe('isUndefined', () => {\n    const definedVariable = 1; //defined variable (will return false)\n    let undefinedVariable; //undefined variable (will return true)\n\n    it('_.isUndefined(definedVariable)', () => {\n      assert.equal(_.isUndefined(definedVariable),\n        (definedVariable === undefined))\n    });\n\n    it('_(definedVariable).isUndefined()', () => {\n      assert.equal(_(definedVariable).isUndefined(),\n        (definedVariable === undefined))\n    });\n\n    it('_.isUndefined(undefinedVariable)', () => {\n      assert.equal(_.isUndefined(undefinedVariable),\n        (undefinedVariable === undefined))\n    });\n\n    it('_(undefinedVariable).isUndefined()', () => {\n      assert.equal(_(undefinedVariable).isUndefined(),\n        (undefinedVariable === undefined))\n    });\n\n  });\n\n  describe('flatten', () => {\n\n    it('_.flatten(twoLayerArray)', () => {\n      const testArray = [1,2[3,4]];\n      assert.deepEqual(_.flatten(testArray),\n        testArray.reduce((a,b) => a.concat(b), []))\n    });\n\n    it('_.flatten(multiLayerArray)', () => {\n      const testArray = [1,2[3,4,[5,6,[7,8]]]];\n      assert.deepEqual(_.flatten(testArray),\n        testArray.reduce((a,b) => a.concat(b), []))\n    });\n\n  });\n\n  describe('forEach', () => {\n    it('_.forEach(array)', () => {\n      const testArray = [1,2,3,4];\n\n      let lodashOutput = []\n      let nativeOutput = []\n\n      _.forEach(testArray, element => {\n        lodashOutput.push(element);\n      });\n      testArray.forEach(element => {\n        nativeOutput.push(element);\n      });\n\n      assert.deepEqual(lodashOutput,nativeOutput);\n    });\n\n    it('_.forEach(object)', () => {\n      const testObject = {\n        'one':1,\n        'two':2,\n        'three':3,\n        'four':4,\n      }\n\n      let lodashOutput = []\n      let nativeOutput = []\n\n      _.forEach(testObject, value => {\n        lodashOutput.push(value);\n      });\n\n      Object.entries(testObject).forEach(([key,value]) => {\n        nativeOutput.push(value);\n      });\n\n      assert.deepEqual(lodashOutput,nativeOutput);\n    });\n  });\n\n  describe('startsWith', () => {\n    it(`_.startsWith('abc', 'a')`, () => {\n      assert.deepEqual(\n        _.startsWith('abc', 'a'),\n        'abc'.startsWith('a')\n      );\n    });\n    it(`_.startsWith('abc', 'b')`, () => {\n      assert.deepEqual(\n        _.startsWith('abc', 'b'),\n        'abc'.startsWith('b')\n      );\n    });\n    it(`_.startsWith('abc', 'b', 1)`, () => {\n      assert.deepEqual(\n        _.startsWith('abc', 'b', 1),\n        'abc'.startsWith('b', 1)\n      );\n    });\n  });\n\n  describe('endsWith', () => {\n    it(`_.endsWith('abc', 'c')`, () => {\n      assert.deepEqual(\n        _.endsWith('abc', 'c'),\n        'abc'.endsWith('c')\n      );\n    });\n    it(`_.endsWith('abc', 'b')`, () => {\n      assert.deepEqual(\n        _.endsWith('abc', 'b'),\n        'abc'.endsWith('b')\n      );\n    });\n    it(`_.endsWith('abc', 'b', 2)`, () => {\n      assert.deepEqual(\n        _.endsWith('abc', 'b', 2),\n        'abc'.endsWith('b', 2)\n      );\n    });\n  });\n\n  describe('throttle', () => {\n    function throttle(func, timeFrame) {\n      var lastTime = 0;\n      return function () {\n        var now = new Date();\n        if (now - lastTime >= timeFrame) {\n          func();\n          lastTime = now;\n        }\n      };\n    }\n\n    it('throttle is not called more than once within timeframe', () => {\n      let callCount = 0;\n      const fn = throttle(() => callCount++, 100);\n\n      fn();\n      fn();\n      fn();\n\n      assert.equal(callCount, 1);\n    });\n  })\n\n  describe('isFunction', () => {\n    function isFunction(func) {\n      return (func && typeof func === \"function\")\n    }\n\n    it('_.isFunction(setTimeout)', () => {\n      assert.deepEqual(_.isFunction(setTimeout),\n        isFunction(setTimeout))\n    });\n\n    it('_.isFunction(1)', () => {\n      assert.deepEqual(_.isFunction(1),\n        isFunction(1))\n    });\n\n    it('_.isFunction(abc)', () => {\n      assert.deepEqual(_.isFunction(\"abc\"),\n        isFunction(\"abc\"))\n    });\n\n  });\n\n  describe('unionBy', () => {\n    function unionBy(...arrays) {\n      const iteratee = (arrays).pop();\n\n      if (Array.isArray(iteratee)) {\n        return []; // return empty if iteratee is missing\n      }\n\n      return [...arrays].flat().filter(\n        (set => (o) => set.has(iteratee(o)) ? false : set.add(iteratee(o)))(new Set()),\n      );\n    };\n\n    it('should take an iteratee function', () => {\n      assert.deepStrictEqual(_.unionBy([2.1], [1.2, 2.3], Math.floor), unionBy([2.1], [1.2, 2.3], Math.floor));\n    });\n\n    it('should output values from the first possible array', () => {\n      assert.deepStrictEqual(_.unionBy([{ x: 1, y: 1 }], [{ x: 1, y: 2 }], (x) => x.x),\n        unionBy([{ x: 1, y: 1 }], [{ x: 1, y: 2 }], (x) => x.x));\n    });\n  });\n\n  describe('capitalize', () => {\n    function capitalize(string) {\n      return string ? string.charAt(0).toUpperCase() + string.slice(1).toLowerCase() : '';\n    }\n\n    it('_.capitalize(\"FRED\")', () => {\n      assert.deepStrictEqual(_.capitalize(\"FRED\"), capitalize(\"FRED\"));\n    });\n\n    it('_.capitalize(\"fred\")', () => {\n      assert.deepStrictEqual(_.capitalize(\"fred\"), capitalize(\"fred\"));\n    });\n\n    it('_.capitalize(\"HELLO WORLD\")', () => {\n      assert.deepStrictEqual(_.capitalize(\"HELLO WORLD\"), capitalize(\"HELLO WORLD\"));\n    });\n\n    it('_.capitalize(\"hello world\")', () => {\n      assert.deepStrictEqual(_.capitalize(\"hello world\"), capitalize(\"hello world\"));\n    });\n  });\n\n  describe('defaults', () => {\n    it('sets up default values the same way', () => {\n      const defaultValues = { a: 1, b: 2, c: 3 };\n      const givenValues = { b: 4 };\n\n      const lodashObject = _.defaults(givenValues, defaultValues);\n      const vanillaObject = Object.assign({}, defaultValues, givenValues);\n\n      assert.deepStrictEqual(vanillaObject, { a: 1, b: 4, c: 3});\n      assert.deepStrictEqual(vanillaObject, lodashObject);\n    });\n\n    it('should handle nested values equally', () => {\n      const defaultValues = { a: 1, b: 2, c: { x: 3, y: 4 } };\n      const givenValues = { c: { x: 5 } };\n\n      const lodashObject = _.defaults(givenValues, defaultValues);\n      const vanillaObject = Object.assign({}, defaultValues, givenValues);\n\n      assert.deepStrictEqual(vanillaObject, { a: 1, b: 2, c: { x: 5 } })\n      assert.deepStrictEqual(vanillaObject, lodashObject);\n    });\n  });\n\n  describe('last', () => {\n    it('_.last([1,2,3,4,5])', () => {\n      assert.deepEqual(_.last([1,2,3,4,5]), [1,2,3,4,5].at(-1));\n    });\n    it('_.last([])', () => {\n      assert.deepEqual(_.last([]), [].at(-1));\n    });\n  });\n  describe('first', () => {\n    it('_.first([1,2,3,4,5])', () => {\n      assert.deepEqual(_.first([1,2,3,4,5]), [1,2,3,4,5].at(0));\n    });\n    it('_.first([])', () => {\n      assert.deepEqual(_.first([]), [].at(0));\n    });\n  })\n  describe('head', () => {\n    it('_.head([1,2,3,4,5])', () => {\n      assert.deepEqual(_.head([1,2,3,4,5]), [1,2,3,4,5].at(0));\n    });\n    it('_.head([])', () => {\n      assert.deepEqual(_.head([]), [].at(0));\n    });\n  })\n});\n"
  }
]