JavaScript miscellaneous
Chrome console & Debugging
Chrome console .. & debuging in chrome ..
- logging with
console.log(...)
- breakpoints &
debugger
cmd, execution tracking …
‘use strict’
To enable ES5
- off by default — always put
'use script'
on top of script/fn-body- auto enable for
class
&module
- no way to cancel once enter strict mode
- auto enable for
- non-strict: assignment to non-existing var (without declear) ==> create a new global var (for compatibility) ..
Data types
Object
key: str/symbol (keyed values collection)Array
key: int (ordered collection, MDN)Map
key: any typeSet
: unique values
Date & time
- creation &
Date.parse(str)
.. - get/set date components:
get/set*()
, auto-correction - work on timestamp
- tasks: Show a weekday & European weekday, getDateAgo(date, days), getLastDayOfMonth(year, month)
Map & Set, WeakMap & WeakSet
Map
: obj with key of any type, key compare: ===
& NaN === NaN
new Map([ [_,_], [_,_] ..])
& obj <=> map:new Map(Object.entries(obj))
.. &Object.fromEntries(map)
..- iter:
forEach(..)
,keys/values/entries()
..
Set
: unique values
- methods similar to map, get/set() => add(), iter by insertion order ..
- Filter unique array members:
Array.from(new Set(arr))
..
WeakMap
/WeakSet
: obj unreachable by other means -> rmed from memory & WM/WS
- only obj as key/items in WM/WS
- methods ..
- WeakMap use cases: additional data, caching
Obj advanced
Symbol type
unique (even same desc) vs global symbol (1 key 1 symbol)
1 | alert(Symbol("id")); // TypeError (not auto-convert to string) |
Obj prop config
prop descriptor: value
+ writable
, enumerable
, configurable
..
- get/set desc:
Object.getOwnPropertyDescriptor()
,Object.defineProperty()
& clone with desc .. - obj created “the usually way”: flags default
true
; flags not supplied in desc defalutfalse
- built-in
toString()
non-enumerable - Sealing an object globally …
Accessor get/set xxx([value]) {..}
, trigger when xxx
prop read/assign
- desc:
get/set([value]) {..}
,enumerable
,configurable
- smarter g/setter: store value in another internal prop
- age -> birthday example ..
Key iter
- method differs (all return an arr) .., ..
Reflect.ownKeys(obj)
/obj.hasOwnProperty(key)
: ownObject.getOwnPropertyNames
: own, non-symbol —Object.getOwnPropertySymbols(obj)
: own, symbolObject.keys/values/entries(obj)
: own, non-symbol &enum
for..in
: own + proto, non-symbol &enum
Object.assign()
: symbol + non-symbol ..
Global obj
Provide built-in var & fn (can be access directly), e.g. window
in browser & global
in node
- e.g.
window.alert
,window.innerHeight
& global fn || var-var - make value global:
window.xxx = ...
(props of global-obj)
Primitive as Obj
provide methods to op prim but keep them fast & lightweight e.g. String
, Number
, Boolean
, Symbol
- temporary wrapper obj created & destroyed .. — manually modify obj wrap => err (strict) || undefined ..
Obj to primitive
- 3 hints:
"string"
,"number"
&"default"
(no boolean hint: all obj => true) - 3 methods: must return a prim value ..
[Symbol.toPrimitive](hint)
return obj ==> err- built-in
toString()
=> “[object Object]”,valueOf()
=> obj itself (ignored) ..
JS engine internal: Event loop
Macrotask queue: handle tasks e.g. current rgl sync script, external script load & exe, UI/network event handler (e.g. mousemove
), setTimeout callback
- tasks come while engine busy — enqueued to the queue
- re-render only af task complete — if current task tasks long time: Page Unresponsive alert
- enqueue a macrotask:
setTimeout(f)
- use case: split CUP-heavy task by setTimeout => react other tasks in-btn / progress indication …
Microtask queue (aka PromiseJobs
queue): handle async promise handlers in .then/catch/finally
& await
- handler enqueued when promise settled, run af current code & prev micro finished ..
- global
unhandledrejection
event: triggered when microtask queue completed but exist “rejected” promise - make code exe af
.then/catch/finally
: chained by.then()
- enqueue a microtask —
queueMicrotask(f)
..
JS exe-flow based on event loop: engine sleep until tasks appear, then exe from the oldest one (FIFO) ..
- exe process (no macrotask in-btw microtask — ensure app-env same) ..
- current rgl sync script (=> all microtasks => render)
- some macrotask (=> all microtasks => render)
- another macrotask
- …
- cpu-heavy event & web worker: another thread
Popup win & iframe
Popup win: window.open(URL, ..)
.. — open a new tab (by default) in browser (or win if sizes provided ..)
- win <-> popup:
let popupWin = window.open(..);
..,popupWin.opener
.. - close popup:
win.close()
&win.closed
(status check) .. - win focus/blur:
win.focus/blur()
&win.onfocus/onblur
.. - win scrolling & resizing …
Embedded win: <iframe ..>
— iframe.contentWindow/contentDocument
..
- wrong doc pitfall:
iframe.contentDocument
wheniframe.onload
(wrong for the one immediately af iframe created) .. window.frames
(named coll) & win hierarchy (iframe contains iframes) — check whether iframe bywin === top
..- iframe
sandbox
attr (exclude certain actions inside iframe) … - transparent iframe & clickjacking attack (intercept a single click ..) …
Bin data, files
meet binary data: files/img (create, upload, download) ..
BufferSource
ArrayBuffer(byteLength)
: store raw bin data (byte-seq) — read data by 2 kindsArrayBufferView
..BufferSource
: ArrayBuffer + ArrayBufferView ..- str <=> bytes:
textEncoder.encode(str)
(utf-8) &new TextDecoder(encoding, ..).decode(BufferSource, ..)
..
Blob
Blob
bin data type …: file up/download op & web network request ..
- Blob type
'text/html | text/plain'
→Content-Type
in network requests - Blob → URL (for
<a>/<img>
) …
<a download="hello.txt">
,a.href = URL.createObjectURL(blob)
a.click()
,URL.revokeObjectURL(a.href)
- img → Blob (via
<convas>
) …
File & FileReader
File
: inherit fromBlob
, get frominput.files[0]
& Drag’n’Drop events ..FileReader
: read data fromBlob
viafr.readAs*(blob)
(async),load/error
events &fr.result / error
..- sent file over network:
Fetch
/XHR
..
URL object
new URL(url: str, [base])
, url components, char encoding …
Web Components
Custom HTML elem
- all-new: extends
HTMLElement
.. (no semantics ..)- 2-step creation: JS class +
customElements.define(tag, js-class)
… <time-formatted>
&Intl.DateTimeFormat(..)
demo …
- 2-step creation: JS class +
- customized: extends built-in elem (with semantics) — 3-step creation (
<button is="my-button">
) … - html tag
<my-element>
/document.createElement(..)
: create instance ofMyElement
.. - CSS selector
:not(:defined)
: style “undefined” elems, e.g. custom html-tag bfcustomElements.define(..)
.. - HTML parser process parent bf child …
- access childElem by
setTimeout(..)
(af html parsing completed) - want outer callback trigger af inner elem ready: inner elem dispatch events & outer listen
- access childElem by
- task: Live timer elem
Shadow DOM
- Shadow tree (for encapsulation: own id/quary spaces, styling .., ..) vs Light tree …
- create by
elem.attachShadow(..)
=> shadow root:elem.shadowRoot
- if elem has both -> only render shadow — compose by slot …
- create by
- styling:
:host*
,::slotted
, components custom CSS props … &pseudo
attr .. - event handling: event happen in shadow DOM hidden to outside — retarget (bubble) to its host elem ..
- evebt bubbling:
e.composedPath()
,e.composed
(true for bubble across shadow DOM boundary) …
- evebt bubbling:
Template elem
<template>
tag: for HTML markup storage (any syntax-valid HTML), content ignored by browser ..
- elems not render, style/script not work, until
tmpl.content
:DocumentFragment
.. inserted to doc
Generator
Regualr fn retur 1 value ==> Generators “yield” mtp values 1-by-1 (allow create data stream)
1 | function* generateSequence() { // generator function |
- when called, it return a Generator (an Iterator with next() method) to manage the fn-exe
gen.next()
— run fn-exe untilyield <value>
stmt & return{value: <value>, done: true/false}
- use generator to create iter-obj
- can use
gen
infor..of
loop & sperad syntax to get yield values (exc returned value)
- pass data back to gen.yield
gen.next(arg)
— passarg
as the value of current yield & return the resulting-obj of next yield ..gen.throw(err)
— throw err as the result of current yield (err not catched in gen() will fall out togen.throw
)
- Generator composition — embed gen-values into another gen-fn by
yield* gen(...)
- Task: pseudoRandom(seed)
Async iteratable async *[Symbol.asyncIterator]()
async function*
for async gen — yield value asyncly &await gen.next()
[Symbol.asyncIterator]()
for async iterator — iter over data that comes asyncly (e.g. paginated data) & use infor await ..of
loop- the
async function* fetchCommits(repo)
example
Programming pattern
Fn decorator ..
- fn-wrapper that takes fn as param (callback) and alters its behavior
- decorated fn lose prop —
Proxy
( forward eth to target) .. - tasks: spy(fn), delay(fn), debounce(fn, ms), throttle(fn, ms)
Currying
- transform
f(a, b, c)
→f(a)(b)(c)
— easily for partial (see below): let fn = f(a), then fn(b)(c) .. - implementation ..
Proxy & ReflectProxy
: a wrapper obj that intercepts ops (e.g. get/set props) on the target-obj by its handler (obj with traps) ..
- ops on
proxy
=> trigger crp trap => (if no) forwards ops totarget
.. - proxy no own props, access from
target
.. - ops -> proxy handler methods -> internal methods (low level)
- Proxying a getter with
receiver
byReflect.get(target, prop, receiver);
: passreceiver
(correct obj) asthis
in getter …
Reflect
: to complement Proxy …
Tasks: array[-1], makeObservable(target)
Recursion ..
- base (get result without nest calls) & recursive step
- recursive vs iterative ..
- recursive: take resrcs but simpler code
- iterative: memory-saving
- recursive structure & linked list:
node = {value, next -> node2 / null}
- task: Fib numbers, Sum 1..n, Print list, Print list revresely
DOM
- range & selection ..
- mutation observer: fire callback when change observed on a DOM node, childList & subtree, attributes, text content ..
- div
contentEditable
attr
- div
Module
module in browser: <script type="module">
..
type
attr enableimport/export
.., .. — the old “nomodule” attr ..- module
defer
.. by default .., canasync
.. (work for both inline/external scripts .., ..)
export/import
syntax ..
- default export (import without
{}
) vs named export .. default
keyword for default export … (when import, any name works — naming consistency: crp to file name ..)as
for export/import renaming- Re-export:
export .. from ..
(import & export): single entry point of fnality (mtp re-export stmt in 1 file) .. import "module"
: run module code without assign to var
dynamic imports import(<module-path>)
: return a promise resolves into a module-obj with exports (as keys) ..
- a special syntax, not a fn (like super(), cannot copy & use call/apply)
- work with rgl
<script>
tag (no need type=”module”)
module vs rgl script ..
- auto strict (
this == undefined
) - own scope (interchange fnality via
import/export
..) - exe only once & export share when imported mtp times (use as init)
others
- place of
import/export
stms not matter (script top or bottom), but not work inside “{…}” — dynamic imports .. import.meta
: obj contains info about the current module ..- build tool (for deployment) e.g. webpack (bundle modules together & tree-shaking) ..
- resulting “bundled” script
bundle.js
noimport/export
stmt ==> notype=module
required (rgl scriptsrc="bundle.js"
) ..
- resulting “bundled” script
Other concepts & Resources
- code style & linter
- Auto-testing lib & BDD
- Manuals & specs
- Polyfill & Babel
- JS keep evolving & some features may not implemented in all engines
- Babel: transpiler (new syntax constructs) + polyfill (updates/adds new fns)
- Langs “over” JS