{"id":22088206,"url":"https://github.com/hchiam/learning-js","last_synced_at":"2025-07-24T18:33:43.751Z","repository":{"id":37392267,"uuid":"77972659","full_name":"hchiam/learning-js","owner":"hchiam","description":"Miscellaneous practice code in JavaScript. ","archived":false,"fork":false,"pushed_at":"2024-11-26T04:09:37.000Z","size":2579,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-11-26T05:19:55.608Z","etag":null,"topics":["a11y","computer-science","eslint","javascript","jest","js","minify","node","nodemon","npm","plato","prettier","service-worker"],"latest_commit_sha":null,"homepage":"https://github.com/hchiam/learning-js#learning-javascript","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hchiam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-01-04T02:29:26.000Z","updated_at":"2024-11-26T04:09:40.000Z","dependencies_parsed_at":"2023-11-07T05:12:51.841Z","dependency_job_id":"72ac7d14-5d4a-4826-89bf-e35686b4eda2","html_url":"https://github.com/hchiam/learning-js","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hchiam%2Flearning-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hchiam%2Flearning-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hchiam%2Flearning-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hchiam%2Flearning-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hchiam","download_url":"https://codeload.github.com/hchiam/learning-js/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227470102,"owners_count":17778930,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["a11y","computer-science","eslint","javascript","jest","js","minify","node","nodemon","npm","plato","prettier","service-worker"],"created_at":"2024-12-01T02:07:49.360Z","updated_at":"2025-07-24T18:33:43.325Z","avatar_url":"https://github.com/hchiam.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Learning JavaScript\n\nMiscellaneous practice code in JS.\n\nJust one of the things I'm learning. \u003chttps://github.com/hchiam/learning\u003e\n\n\u003chttps://random-code-tips.surge.sh\u003e\n\n## Broaden JavaScript knowledge\n\n\u003chttps://javascript.info/\u003e\n\ne.g.:\n\n- \u003chttps://javascript.info/weakref-finalizationregistry\u003e\n- \u003chttps://javascript.info/proxy\u003e\n- \u003chttps://javascript.info/currying-partials\u003e\n\n### ReqBin - test API endpoints by making API requests\n\n\u003chttps://reqbin.com/\u003e - also shows a bunch of example requests like GET with bearer token auth header, or Curl/JS/Python/PHP/REST/POST/JSON/POST/PATCH/PUT/DELETE\n\n\u003chttps://reqbin.com/json-formatter\u003e\n\n\u003chttps://reqbin.com/json-formatter\u003e\n\n## How to Run .js Files Using Terminal/CommandLine\n\nMake sure to include console.log(\"output text here\");\n\n    node filename.js\n\n## Learn about Modern ES6 JS Features\n\nES6 (ECMAScript 2015) started in **2015**, with yearly additions after that: \u003chttps://www.w3schools.com/js/js_versions.asp\u003e\n\n\u003chttps://stackoverflow.blog/2019/09/12/practical-ways-to-write-better-javascript\u003e\n\nAlso note the stuff around the default values for function arguments here: \u003chttps://devhints.io/es6?ref=devawesome.io\u003e\n\n[Support Both Legacy JS and Modern JS Without Slowing All Browsers](https://codepen.io/hchiam/pen/mdWGLNE)\n\n## Bonus\n\n### Automatically format your code upon save\n\nIn VSCode: use the [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) extension, and then in VSCode \u003e Code \u003e Preferences \u003e Settings \u003e search for \"Format on save\" \u003e turn it on with the checkbox\n\nNow it'll automatically format your code, just like the built-in stuff for [Golang](https://github.com/hchiam/learning-golang).\n\n### Get immediate feedback on code errors and style\n\nTo automatically re-run a [.js file](https://github.com/hchiam/learning-js/tree/master/more-like-interview-questions) and the test cases in it whenever you edit that file, copy the .js code into [`index.js`](https://github.com/hchiam/learning-eslint-google/blob/master/index.js) in my [ESLint repo](https://github.com/hchiam/learning-eslint-google) and do the setup so you can run this command just once:\n\n```bash\nnodemon -x 'npm run lint; node index.js'\n```\n\n**_Or_** `nodemon -x 'npm run lint; npm run test; node index.js'`\n\n**_Or_** `nodemon -x 'jest lowestIndexSameAsValue.test.js'` for example, to re-run the tests just for one file.\n\nThis works just like [`rerun` for Python](https://github.com/hchiam/learning-python/blob/master/README.md#run-code-linter).\n\n**Alternatively:**\n\nTo set up [eslint and jest](https://github.com/hchiam/eslint-and-jest) locally inside this learning-js folder:\n\n```bash\nnpm install jest --global\nnpm install # eslint is already listed in package.json for you\nnpm test # runs scripts test command listed in package.json\n```\n\n**_Or_** just run this: [`jest`](https://github.com/hchiam/learning-jest).\n\n**_Or_** to run just a-specific.test.js, run this: `jest a-specific.test.js`.\n\nYou can also automatically include code style fixes in your commits with [`lint-staged`](https://github.com/hchiam/learning-lint-staged) set up with `husky`.\n\n### Get code Maintainability Index (MI score)\n\nThe MI combines lines of code, cyclomatic complexity, and the Halstead volume metric (i.e. number of variables, operations, decision paths, and lines of code). After you [`npm install -g plato` or `yarn global add plato`](https://github.com/es-analysis/plato), you can get the MI score of your code:\n\n```bash\nplato -r -d report index.js\n```\n\nSimilar to how I use [`radon`](https://github.com/hchiam/learning-python/#maintainability-index-mi-score) for Python code.\n\n### Minify code\n\nInstall `minify`:\n\n```bash\nnpm i minify -g # or: yarn global add minify\nminify -v\n```\n\nUse `minify`:\n\n```bash\nminify minify-this-script.js \u003e minified-script.js\n```\n\n### stuff you can do without JS-heavy web frameworks\n\n\u003chttps://codepen.io/hchiam/pen/ExbmjEP\u003e\n\n### Using [`yarn`](https://github.com/hchiam/learning-yarn) instead of `npm`\n\n```bash\nyarn # instead of npm install or npm run install\nyarn test # instead of npm test\n```\n\nInstead of `nodemon -x 'npm run test; node index.js'`, you can do:\n\n```bash\nnodemon -x 'yarn test; node index.js'\n```\n\n### Service Workers\n\nLearning about them: \u003chttps://github.com/hchiam/learning-service-workers\u003e\n\n### A list of useful one-liner utilities\n\n\u003chttps://1loc.dev/\u003e\n\n### Interesting [a11y](https://github.com/hchiam/web-accessibility-course-notes)-related JS code\n\n\u003chttps://github.com/hchiam/keyboard-focus-trap\u003e\n\n\u003chttps://github.com/hchiam/flying-focus\u003e\n\n### More data structures/algorithms\n\n\u003chttps://github.com/hchiam/learning-splay-tree\u003e\n\n\u003chttps://github.com/hchiam/learning-b-tree\u003e\n\n\u003chttps://github.com/hchiam/learning-skip-list\u003e\n\n\u003chttps://github.com/hchiam/learning-bloom-filter\u003e\n\n\u003chttps://github.com/hchiam/learning-union-find\u003e\n\n\u003chttps://github.com/hchiam/learning-suffix-tree\u003e\n\n\u003chttps://github.com/hchiam/learning-lzw\u003e\n\n### Chrome dev tools tricks for more productive debugging\n\n\u003chttps://www.youtube.com/watch?v=hdRDTj6ObiE\u003e\n\n\u003chttps://blog.bitsrc.io/10-tips-to-improve-productivity-using-chrome-dev-tools-7918fc8203f3\u003e\n\nand tips like this: \u003chttps://umaar.com/dev-tips/15-dollar-zero\u003e\n\n`$_` = previous value\n\n`$0`, `$1`, `$2`, `$3`, `$4` = the last 5 DOM elements you clicked on in the Elements tab\n\n`$('some_selector')` = shortform for `document.querySelector('some_selector')`\n\n`$$('some_selector')` = shortform for `document.querySelectorAll('some_selector')`\n\n`$(`some_selector`, ancestorElement)` or `$('some_selector', $0)`\n\n`$x('some_x_path')` = XPath\n\n`inspect($('some_selector')[0]);` jumps to Elements panel (jQuery not required for that `$`). Works in Firefox too.\n\n`queryObjects(YourConstructor)` = all objects created by `YourConstructor`\n\n`getEventListeners($0)` = get event listeners on the element you last clicked on in Elements tab\n\n- `getEventListeners(htmlElement)` in Chrome\n- **Inspector tab** shows \"`event`\" buttons next to elements in Firefox - \u003chttps://bugzilla.mozilla.org/show_bug.cgi?id=1164285\u003e\n\n`monitorEvents(element, eventName)` = prints captured events\n\n`unmonitorEvents(element)`\n\n`monitor(functionName)` = prints function call with arguments, and also output\n\n`unmonitor(functionName)`\n\n`table()` (shortcut in Chrome) = `console.table()`\n\n- ```js\n  console.table([\n    { a: 1, c: \"hi\" },\n    { a: 3, b: 2 },\n  ]);\n  /**\n   * (index)  a     c     b\n   * 0        1     'hi'\n   * 1        3           2\n   */\n  ```\n\n`clear()` = `console.clear()`\n\n`keys()` = `Object.keys()`\n\n`values()` = `Object.values()`\n\n`copy()` = copies to clipboard any value/object/element inside it.\n\nMore: \u003chttps://developers.google.com/web/tools/chrome-devtools/console/utilities#geteventlisteners\u003e\n\n### Edit any website (temporarily on the client side)\n\nEnter this into the console log in dev tools: `document.designMode='on'`\n\n### Read a file\n\nIn the browser:\n\n- \u003chttps://github.com/hchiam/learning-js/blob/master/read-text-file.js\u003e or\n- \u003chttps://github.com/hchiam/learning-js/blob/master/read-json-file.js\u003e\n\nIn the console terminal CLI:\n\n- \u003chttps://github.com/hchiam/learning-nodejs/blob/master/README.md#read-a-local-file-via-console-cli\u003e\n\n### Compare JSON files\n\n\u003chttps://codepen.io/hchiam/pen/RwXqxwZ\u003e\n\n- edited\n- deleted\n- added\n\n### Get a lot of the functions and jQuery event listeners in a script string\n\n\u003chttps://github.com/hchiam/getFunctions\u003e\n\n### Support modern browsers and older browsers (like IE11) at the same time\n\n```html\n\u003c!-- No need for special server setup or user agent sniffing! --\u003e\n\u003cscript type=\"module\" src=\"modern.js\"\u003e\u003c/script\u003e\n\u003cscript nomodule src=\"legacy.js\"\u003e\u003c/script\u003e\n\u003c!-- https://www.youtube.com/watch?v=cLxNdLK--yI --\u003e\n```\n\n### Evergreen browsers\n\nConclusions:\n\n- Chrome: was always evergreen (2008) = Chrome 1.\n- Safari: quasi-evergreen (2013) = Safari 7 BUT you need to have your Mac settings set to automatically download and install updates.\n- Firefox: rapid releases in 2011, silent updater in 2012 v15, but automated update feature in 2005 = Firefox 1.5 = effectively Firefox 1.\n- Edge: the Chromium-based version of Edge (vs Edge Legacy) was released in 2020 = Edge 79 (some time after Edge Legacy 44).\n- IE: seems like IE 11 but also Microsoft dropped support for IE, so you stop supporting IE = N/A now.\n- detecting basic stuff like browser and major version in `navigator.userAgent` is currently (2024) still available\n  - even in Chrome's user agent reduction: \u003chttps://developers.google.com/privacy-sandbox/blog/user-agent-reduction-android-model-and-version\u003e\n  - whereas Chrome's `navigator.userAgentData` is currently (2025) not adopted in other browsers: \u003chttps://developer.mozilla.org/en-US/docs/Web/API/Navigator/userAgentData#browser_compatibility\u003e\n  - why migrate to User-Agent Client Hints: \u003chttps://developers.google.com/privacy-sandbox/protections/user-agent\u003e\n  - how migrate to User-Agent Client Hints: \u003chttps://web.dev/articles/migrate-to-ua-ch\u003e\n\nReferences:\n\n- \u003chttps://nordvpn.com/cybersecurity/glossary/evergreen-browser/\u003e\n- \u003chttps://css-tricks.com/evergreen-does-not-mean-immediately-available/\u003e\n- \u003chttps://support.mozilla.org/en-US/questions/1058530\u003e\n- \u003chttps://en.wikipedia.org/wiki/Firefox_early_version_history\u003e\n- \u003chttps://wiki.mozilla.org/Silent_Update_updater\u003e\n- \u003chttps://website-archive.mozilla.org/www.mozilla.org/firefox_releasenotes/en-us/firefox/releases/1.0?flang=es-MX\u003e\n- \u003chttps://website-archive.mozilla.org/www.mozilla.org/firefox_releasenotes/en-us/firefox/releases/1.5\u003e\n- \u003chttps://phys.org/news/2005-12-firefox.html\u003e\n- you can make Mac automatically download AND install updates: \u003chttps://support.apple.com/en-ca/guide/mac-help/mchla7037245/mac\u003e\n- \u003chttps://en.wikipedia.org/wiki/Microsoft_Edge_Legacy\u003e\n- \u003chttps://superuser.com/questions/1552847/what-version-of-edge-marked-the-start-of-using-chromium-internally\u003e\n  - This superuser answer may be helpful for detecting pre-Chromium-based Edge Legacy.\n- \u003chttps://www.w3schools.com/browsers/browsers_explorer.asp#edgeinfo\u003e\n- \u003chttps://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-it-pro/internet-explorer-11/ie11-deploy-guide/ie11-delivery-through-automatic-updates\u003e\n\n### Bookmarklets\n\nOnly use them after you read and understand the contents of each bookmarklet!\n\n\u003chttps://en.wikipedia.org/wiki/Bookmarklet\u003e\n\n\u003chttps://github.com/hchiam/learning-js/tree/master/bookmarklets#bookmarklets\u003e\n\n### `this` keyword in old-school functions vs the newer arrow functions\n\n`this` in `function()` = caller. Useful if you want `this` to change to whatever calls your one function.\n\n`this` in `() =\u003e {}` = owner. Useful if you want `this` to always be the creator of the function. I think _nested_ arrow functions also pass along `this`, which you might like.\n\n```js\n// https://www.freecodecamp.org/news/the-difference-between-arrow-functions-and-normal-functions/\nconst obj = {\n  a: () =\u003e {\n    console.log(this);\n    console.log(\n      `\"this\" will be whatever \"this\" was before the function was created`\n    );\n  },\n  f: function () {\n    console.log(this);\n    console.log(`\"this\" will be the current object that contains the function`);\n  },\n};\nobj.a();\nobj.f();\n```\n\n### CJS vs MJS/ESM/ES6M vs all the other types of JavaScript modules syntax\n\n- ESM = `import` and `export`. Simplest, async, tree-shakeable, but not universally compatible.\n  - more info, like `export default ...` and `import * from '...'` vs `import * as ... from '...'` and dynamic import in vanilla JS, and more: \u003chttps://www.patterns.dev/vanilla/module-pattern/\u003e\n- UMD = works everywhere, is more of a pattern of fallbacks, usually the fallback when ESM fails.\n- CJS = `require` and `module.exports`, sync, good for BE, commonly seen for node stuff.\n- AMD = `define`, async, good for FE, confusing compared to CJS.\n\nRead later:\n\n\u003chttps://www.sitepoint.com/understanding-es6-modules\u003e\n\n\u003chttps://stackoverflow.com/a/46677972\u003e\n\n\u003chttps://dev.to/iggredible/what-the-heck-are-cjs-amd-umd-and-esm-ikm\u003e\n\n\u003chttps://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/\u003e\n\n### [Priority queue](https://github.com/datastructures-js/priority-queue) which can be used as a min heap or max heap\n\n```js\n// in CJS syntax:\nconst {\n  MinPriorityQueue,\n  MaxPriorityQueue,\n} = require(\"@datastructures-js/priority-queue\");\n```\n\nor\n\n```js\n// in ESM syntax:\nimport {\n  MinPriorityQueue,\n  MaxPriorityQueue,\n  PriorityQueueOptions, // queue options interface\n  PriorityQueueItem, // queue item interface\n} from \"@datastructures-js/priority-queue\";\n```\n\nAPI usage example:\n\n```js\nconst pqAsHeap = new MinPriorityQueue();\npqAsHeap.enqueue(num);\npqAsHeap.dequeue().element;\npqAsHeap.size();\npqAsHeap.front().element;\n```\n\n### add [type checking even in JS files](https://code.visualstudio.com/docs/nodejs/working-with-javascript#_type-checking-javascript), no config necessary (in VSCode)\n\nJust add this comment to the top of your JS file:\n\n```js\n// @ts-check\n```\n\n### Scope console log scripts in DevTools to an iframe or other environment\n\nChrome:\n\n![scope_dev_tools_chrome.png](scope_dev_tools_chrome.png)\n\nFirefox:\n\n![scope_dev_tools_firefox.png](scope_dev_tools_firefox.png)\n\n### Regex and ReDoS security\n\n- avoid evil RegEx, avoid exponential backtracking, avoid ReDoS: \u003chttps://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS\u003e\n\n### Regex cheatsheet\n\n\u003chttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet\u003e\n\n- `x(?=y)` = lookahead _(AKA **positive** lookahead, in contrast to negative lookahead)_ = \"match x if followed by y\"\n- `x(?!y)` = **negative** lookahead = \"match x if NOT followed by y\"\n- `(?\u003c=y)x` = lookbehind _(AKA **positive** lookbehind, in contrast to negative lookbehind)_ = \"match x if preceded by y\"\n- `(?\u003c!y)x` = **negative** lookbehind = \"match x if NOT preceded by y\"\n- `(?:x)` = **noncapturing** group = \"match x but don't remember the group\"\n- `(?\u003cName\u003ex)` = capture group with name `Name`\n- `\\n` = reference to the nth capture group match (count the left brackets)\n- `\\k\u003cName\u003e` = reference to the capture group with name `Name` (note: `\\k` is not some variable, it's literally like replacing the \"`?`\")\n- `^` = start\n- `$` = end\n- `x*` = 0 or more times (mnemonic: `*` looks more like a 0 than `+` does, and `*0` changes a number, while `*1` doesn't)\n- `x+` = 1 or more times (mnemonic: `+` looks more like a 1 than `*` does, and `+1` changes a number, while `+0` doesn't)\n- `x?` = 0 or 1 time = \"optionally exists\"\n- `x{n}` = n times\n- `x{n,}` = n or more times\n- `x{n,m}` = n to m times, inclusive\n- `x*?`, `x+?`, `x??`, `x{n}?`, `x{n,}?`, `x{n,m}?` = match non-greedily = \"match minimally\", e.g. `/\u003c.*?\u003e/` only matches `\u003ca\u003e` instead of `\u003ca\u003e\u003c/a\u003e` entirely.\n- `\\b` = \"word boundary\" (note: `/\\w\\b\\w/` can't ever matche anything, but `/\\w\\b\\W\\w/` can)\n  - likely useful as: `/\\bword\\b/g` (replace `word` with your word or word pattern)\n- `[\\b]` = backspace\n- `\\xhh` = character with 2 hexadecimal digits\n- `\\uhhhh` = UTF-16 character with 4 hexadecimal digits\n- `\\u{hhhh}`, `\\u{hhhhh}` (with `u` flag) = Unicode character with 4/5 hexadecimal digits\n  - `'\\u{2713}' === '\\u2713'` but can include other symbols than numbers in brackets\n\nMy applied example: regex to automatically group digits with spaces in input boxes:\n\n- \u003chttps://codepen.io/hchiam/pen/yLrjgrV\u003e (4 digits from left to right, or from right to left)\n- `.split(/(\\d{4})/g)` --\u003e `.replace(/\\D/g,'').split(/(\\d{4})/g).filter(x=\u003ex).join(' ')`\n  - `1234567890` --\u003e `1234 5678 90`\n\n### Web Locks\n\n```js\n// multiple browser tabs can try to access a lock named my_resource, but only one will be processed at a time (queued)\n// also scoped to origins (https://example.com is different from https://example.org:8080)\nnavigator.locks.request(\"my_resource\", async (lock) =\u003e {\n  // lock acquired\n\n  // do stuff\n  await do_something();\n  await do_something_else();\n\n  // lock released\n});\n```\n\nNote: deadlocks can still happen if, say, multiple locks are requested out-of-order.\n\nMore details/options: \u003chttps://developer.mozilla.org/en-US/docs/Web/API/Web_Locks_API\u003e\n\n### `import` vs `import()`\n\n[Static `import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import):\n\n```js\nimport { something as aliasedName } from \"some-module.js\";\n```\n\n[Dynamic `import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import):\n\n```js\nimport(\"/some-module.js\").then((aliasedName) =\u003e {});\n// or:\nconst { default: myDefault, foo, bar } = await import(\"/some-module.js\");\n// or just:\nawait import(\"/some-module.js\"); // like if you just want its side-effects\n```\n\n### D3 `\u003cpath\u003e`/svg `.click()` note\n\n```js\n/** Because simply using d3Element.click() or jQuery $(d3Element).click() doesn't work: https://stackoverflow.com/questions/9063383/how-to-invoke-click-event-programmatically-in-d3 */\nfunction triggerD3PathClick(d3Element) {\n  const event = new MouseEvent(\"click\");\n  d3Element.dispatchEvent(event);\n}\n```\n\n### xpath\n\nHere's an xpath to get only the English entry part of a Wiktionary page:\n\n```js\n$x(\n  \"//h2[span[text()='English']] | //h2[span[text()='English']]/following-sibling::*[preceding-sibling::h2[1][span[text()='English']] and not(self::h2)]\"\n);\n// use | so you can include the English h2 in the selection\n// you need the [1] so you stop selecting elements after the next h2\n// you need self:: in not(self::h2) to avoid including the next h2\n```\n\nBuilding on that, here's an xpath to get just the etymology and definition(s) (`\u003cp\u003e` or `\u003col\u003e`) of the English part of a Wiktionary page:\n\n```js\n$x(\n  \"//h2[span[text()='English']]/following-sibling::*[self::p or self::ol][preceding-sibling::h2[1][span[text()='English']]]\"\n);\n```\n\n### Event listener `event.target` vs `event.currentTarget` vs `event.relatedTarget`\n\n\u003chttps://stackoverflow.com/a/10086501\u003e\n\n- `currentTarget` = listening element (e.g. the individual button that has the click event listener fired on it)\n- `target` = triggering element (i.e. maybe the button, or maybe the i or span you actually clicked on inside of the button)\n- my own mnemonic: \"C\" is for \"catcher\", \"T\" is for \"trigger\". also, the longer name is more specific to the \"catcher\" element(s), as opposed to the many more possible \"trigger\" elements/sources.\n\n\u003chttps://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/relatedTarget\u003e\n\n- `relatedTarget` = element focused _to_ for `blur`, focused _from_ for `focus`; similar idea for `focusin` and `focusout` and `mouse`(...)/`drag`(...) events, but note that `relatedTarget` may be `null` for non-focusable elements or for security reasons like tabbing out of a page.\n\n### operator precedence reference\n\nfor example, `\u0026` is evaluated before `\u0026\u0026` before `||`: \u003chttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_precedence#table\u003e\n\n### example of debugging with chrome dev tools and fixing code base\n\n\"Optimizing INP: A deep dive\": \u003chttps://youtu.be/cmtfM4emG5k\u003e\n\n### weird timing behaviour with `try` `catch` `finally`\n\n\u003chttps://jakearchibald.com/2021/last-return-wins/\u003e\n\nThe `finally` console log prints `'two'` \"before\" the `return 'three'`:\n\n```js\n// this code prints out 'one', 'two', 'three', 'four':\n\nfunction finallyTest() {\n  try {\n    console.log(\"one\");\n    return \"three\";\n  } catch (err) {\n    console.log(\"error\");\n  } finally {\n    console.log(\"two\");\n  }\n}\n\nconsole.log(finallyTest());\nconsole.log(\"four\");\n```\n\nThis might cause unexpected timing issues if you're not aware of this. (Also, `​.finally` behaves differently for `Promise`s.)\n\nMore notes on `Promise`s and `async`/`await`: \u003chttps://www.joshwcomeau.com/javascript/promises/\u003e\n\n### Example use of JS animation `ScrollTimeline` that goes dynamically beyond what CSS can do\n\n\u003chttps://web.dev/articles/building/a-tabs-component#animation\u003e\n\n### tag function of template literals string, raw\n\n\u003chttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw\u003e\n\n```js\nvar thisisTrue =\n  String.raw`C:\\folder\\path\\file.js` === `C:\\\\folder\\\\path\\\\file.js`;\n```\n\n```js\n// using new RegExp with String.raw and variable:\nvar x = \"Street\";\n\nconsole.log(new RegExp(`(\\\\d+) ${x}`).exec(\"123 Street\")[1]);\n// '123'\nconsole.log(new RegExp(String.raw`(\\d+) ${x}`).exec(\"123 Street\")[1]);\n// '123'\n```\n\nso:\n\n```js\nnew RegExp(\"d\"); // doesN'T work, requires double back slash\nnew RegExp(\"\\\\d\"); // works, requires double back slash\nnew RegExp(String.raw`\\d`); // works\n```\n\n### space characters\n\nYou might know about `' '` and `\u0026nbsp;`, but did you know about `\u0026puncsp;` (`'\\u2008'`) which takes up space but is able to wrap? there's even more Unicode characters: \u003chttps://stackoverflow.com/questions/8515365/are-there-other-whitespace-codes-like-nbsp-for-half-spaces-em-spaces-en-space\u003e You can also do this in JS: - `'\\u{2713}' === '\\u2713'` but can include other symbols than numbers in brackets\n\n```js\n\"a\".padEnd(10, \"\\u2008\"); // U+2008 is Unicode for \u0026puncsp;\n```\n\n### using JS to set CSS styles\n\n```js\nelement.style.color = \"red\"; // this does something\nelement.style.color = \"red !important\"; // WARNING: this won't do anything! it won't even change the color!\nelement.style.setProperty(\"color\", \"red\", \"important\"); // this works if you want to include !important\n```\n\n### width and height of HTML elements in CSS/JS\n\n\u003chttps://stackoverflow.com/questions/21064101/understanding-offsetwidth-clientwidth-scrollwidth-and-height-respectively\u003e\n\n- offsetWidth, offsetHeight (includes padding and border)\n  - clientWidth, clientHeight (like offsetWidth and offsetHeight but without the padding or border)\n- CSS width, CSS height\n- scrollWidth, scrollHeight (doesn't include padding or border, but does include overflow content)\n\n### remove initial \"1.\" text node without replacing children HTML\n\n```js\n// if first child (likely textNode) starts with \"#.\", then remove that child:\nif (/^\\d+\\.$/.test(element.childNodes[0].nodeValue)) {\n  element.childNodes[0].remove();\n}\n```\n\n### `Set` methods\n\n- \u003chttps://web.dev/blog/set-methods?hl=en\u003e\n  - `aSet.intersection(bSet)`\n  - `aSet.union(bSet)`\n  - `firstSet.difference(notInSecondSet)`\n  - `inAXorB = aSet.symmetricDifference(bSet)`\n  - `fours.isSubsetOf(events)`\n  - `evens.isSupersetOf(fours)`\n  - `haveNothingInCommon = primes.isDisjointFrom(squares)`\n\n## `document.implementation.createHTMLDocument()`\n\n- \u003chttps://www.youtube.com/watch?v=surh_D8CU9A\u0026list=PLNYkxOF6rcIAEVKJ98bDkQRkwvO4grhnt\u0026index=11\u003e\n- \u003chttps://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createHTMLDocument#examples\u003e\n\n```js\noutput.innerHTML = \"\";\nconst doc = document.implementation.createHTMLDocument(); // \u003c-- a key part\ndoc.write(\"\u003cp\u003elist:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\");\noutput.append(doc.body.firstChild); // \u003c-- a key part\n// then to keep appending:\nlet previousLength = 0; // until browser stream chunk implementation detail changes\nfor await (const chunk of stream) {\n  const newContent = sanitized(chunk.slice(previousLength)) + \"\u003cli\u003e\";\n  previousLength = chunk.length;\n  doc.write(newContent); // \u003c-- a key part for streaming instead of replacing all\n}\ndoc.write(\"\u003c/ul\u003e\");\n```\n\nwhich can more performant/streamable than this:\n\n```js\noutput.innerHTML = \"\u003cp\u003ecompletely replacing everything every time\u003c/p\u003e\";\n```\n\nYou can see the difference in Chrome DevTools with Ctrl+Shift+P \u003e Rendering \u003e Paint flashing.\n\n## communicate data between tabs and calling functions on the other tab\n\n- requires the first tab opening the second tab in js code\n\n\u003chttps://stackoverflow.com/questions/1366483/javascript-sharing-data-between-tabs/1367357#1367357\u003e\n\nfirst tab: (opens second tab in js code)\n\n```js\nvar child_window = window.open(\"http://localhost:5173\", \"_blank\");\nvar var_from_child = child_window.some_var;\nchild_window.someFunction(\"with\", \"these\", \"params\");\n```\n\nsecond tab: (opened by first tab in js code)\n\n```js\nvar parent_window = window.opener;\nvar var_from_parent = parent_window.some_var;\nparent_window.someFunction(\"with\", \"these\", \"params\");\n```\n\n\u003chttps://github.com/hchiam/learning-js/tree/main/postMessage\u003e\n\n\u003chttps://github.com/hchiam/recreateVideoInSeparateWindow\u003e (google meet `\u003cvideo\u003e` --\u003e 2nd window `\u003ccanvas\u003e`)\n\n## save SVG in the `\u003cbody\u003e` as a .PNG file\n\n\u003chttps://codepen.io/hchiam/pen/XJrYMNL?editors=1010\u003e\n\n## `unicode-range` can be used to mix fonts or target letters to use different fonts\n\n- CSS+JS mixed font `unicode-range` \"animation\": \u003chttps://codepen.io/hchiam/pen/YPKJKMY?editors=0100\u003e\n\n## why you would use `setTimeout` of `0` seconds\n\n```js\nsetTimeout(() =\u003e {\n  //doSomething();\n}, 0);\n```\n\n- (but also Ctrl+F for `queueMicrotask` in these notes)\n\n\u003chttps://www.youtube.com/watch?v=8aGhZQkoFbQ\u0026t=896s\u003e\n\n- QUICK EXPLANATION: use setTimeout with 0 seconds because event loop queue will be emptied after function call stack is clear\n\n## installable PWA (Progressive Web App) template (uses a service worker)\n\n\u003chttps://github.com/hchiam/pwa-template\u003e\n\n## call stack string\n\n\u003chttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack\u003e\n\n```js\n// note: not a recommended/standardized string - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack\nconst callStack = new Error().stack;\n```\n\n## locally play video with speed control\n\n\u003chttps://codepen.io/hchiam/pen/qEBVLWG\u003e\n\n## Clipboard API (WIDELY AVAILABLE)\n\n    ```js\n    navigator.clipboard.read\n    navigator.clipboard.write\n    navigator.clipboard.writeText(text);\n    navigator.clipboard.readText();\n    ```\n\n## Resize Observer API (WIDELY AVAILABLE)\n\n    ```js\n    const resizeObserver = new ResizeObserver(entries =\u003e {\n      for (const entry of entries) {\n        entry.target;\n      }\n    });\n    resizeObserver.observe(element);\n    ```\n\n## Broadcast Channel API - if same origin (WIDELY AVAILABLE)\n\n    ```js\n    const bc = new BroadcastChannel(name);\n    bc.postMessage(message);\n    const bc = new BroadcastChannel(name);\n    bc.addEventListener('message', event =\u003e {\n      event.data;\n    });\n    ```\n\n## Performance Interface API\n\n    ```js\n    performance.getEntriesByType('navigation'); // (WIDELY AVAILABLE)\n    performance.navigation; // (NOT IN DENO OR NODE.JS)\n    performance.memory; // (NOT IN FIREFOX OR SAFARI)\n    performance.timing; // (NOT IN DENO)\n    ```\n\n## Channel Messaging API (WIDELY AVAILABLE): (more 1-to-1 than Broadcast Channel API)\n\n(available in web workers)\n\n\u003chttps://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API\u003e\n\n## Notifications API\n\n    ```js\n    Notification?.requestPermission().then(permission =\u003e {\n      if (permission === 'granted') {\n        new Notification('hi');\n      }\n    });\n    ```\n\n## Geolocation API\n\n    ```js\n    navigator.geolocation.getCurrentPosition(position =\u003e {\n      position.coords.latitude;\n      position.coords.longitude;\n    });\n    ```\n\n## detect when all images have loaded\n\n`img` has a `.complete` property, so you can check if all `\u003cimg\u003e`s in an HTML container are done loading, and you can do something like the following jQuery code:\n\n```js\ncontainer.find(\"img\").on(\"load\", () =\u003e {\n  if (allImagesLoadingComplete(container)) {\n    callback();\n  }\n});\n\nfunction allImagesLoadingComplete(container) {\n  const images = container.is(\"img\") ? container : container.find(\"img\");\n  return images.toArray().every((img) =\u003e img.complete);\n}\n```\n\n## tasks vs microtasks\n\nThere is a slight difference between `setTimeout` of 0 ms and `queueMicrotask`, but `queueMicrotask` seems more expressive/explicit/intentional in terms of waiting for a task complete to avoid a timing bug - \u003chttps://www.freecodecamp.org/news/queuemicrotask/\u003e = a shorter explanation than the following further reading:\n\n- \u003chttps://developer.mozilla.org/en-US/docs/Web/API/Window/queueMicrotask\u003e\n- \u003chttps://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide\u003e\n- For other related methods and details: \u003chttps://macarthur.me/posts/navigating-the-event-loop/#the-tldr\u003e (see the [TL;DR](https://macarthur.me/posts/navigating-the-event-loop/#the-tldr) first):\n  - setTimeout(() =\u003e {}, 0)\n  - queueMicrotask(() =\u003e {}\n  - requestAnimationFrame(() =\u003e {})\n  - requestIdleCallback(() =\u003e {})\n- \u003chttps://www.youtube.com/watch?v=cCOL7MC4Pl0\u003e\n  - these 3 queues behave slightly differently: \u003chttps://youtu.be/cCOL7MC4Pl0?t=1656\u003e\n  - 1: tasks queue: process one at a time.\n  - 2: animation callbacks queue: process all until completion, except for additional items that were queued during processing, until the next frame.\n  - 3: and microtasks queue: process all until completion, including any additional items that were queued during processing.\n\ncompare with \u003chttps://github.com/hchiam/learning-js/blob/main/event-loop_call-stack_task-queue_microtask-queue.js\u003e\n\n## a list of bunch of quick helpful JS functions\n\n\u003chttps://github.com/devsmitra/javascript-quick-functions\u003e\n\n- generator\n- time to execute\n- array functions\n- number functions\n- string functions\n- date and object functions\n- promise-related functions\n- random hex colour\n- convert px to rem\n- **get selected text**\n\n## take screenshot / screen capture of window and ideally just the viewport\n\n- using `getDisplayMedia` to take an actual screenshot, instead of using html2canvas to try to recreate things:\n\n  - Claude artifact: \u003chttps://claude.ai/public/artifacts/0c4b4813-2b92-42fd-b2e2-a0a47d9fbd18\u003e\n\n  - Claude conversation leading up to that artifact: \u003chttps://claude.ai/share/38b43df5-f5eb-48f6-a8bb-afe287dbd92b\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhchiam%2Flearning-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhchiam%2Flearning-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhchiam%2Flearning-js/lists"}