notes_js
13.9k83NOTES2021-11-17

Algorithm

time complexity

NPM

1
2
3
4
5
6
7
8
9
npm version patch // v1.0.1

npm version prepatch // v1.0.2-0

npm version minor // v1.1.0

npm version major // v2.0.0

npm publish --access public
  • control the files of a ==package==
    • define the file field in the package.json
    • use .npmignore which is used as same as gitignore

the principle of component design

  1. single responsibility principle. to compose complex components by smaller specialized components.
  2. conceals the construction of components, and only reveals the necessary information
  3. To ensure predictability and determinacy of components, always return the same output for a given input
  4. keep loose coupling, instead of tight coupling. Components should have little or no knowledge about others.
  5. composable. Composition is a way to combine components to create a bigger component
  6. reuseable
  7. pure or almost pure function which means no side effects and doesn’t depend on the environment or the global state, such as network or global variables.
  8. isolate the impure code from the pure
  9. straightforward to test
  10. a meaningful name. If a component’s usage is highly specific, its name may contain more words, like <HeaderMenu> <Header>

to judge a component’s level according to usage
1. Reading name and props; best
2. Consulting documentation; good
3. Exploring the code; admissible
4. Asking the author. avoid

performance optimization

  • avid reflow and repaint
  • use prefetch and preload to define js executing order, in order to avoid blocking html rendering.

browser rendering

the rendering process

  • The browser obtains the IP address from the domain name by means of DNS(domain name system) analysis
  • then send a http request to the IP address
  • server receives the request and responds with the html content
  • the browser parses html string and create a dom tree, and then analyzes CSS to CSS rule tress
  • structure the rendering tree(only the nodes that need to be displayed)

GUI rendering thread and JS engine thread

GUI(graphical user interface) rendering thread and JS engine thread are mutual exclusive. download, analysis and execute of JS will stop the rendering process. in other words, when JS is encountered, the rendering process will stop to structure the rendering tree and transfer the control right to JS engine.

reflow and repaint

  1. reflow: when the changes of DOM geometrical size(like width, height, or display) affect the page layout or the position of other elements
  2. repaint: when the style(like color, background) of dom are changed
    if repaint didn’t affect dom geometrical size, then reflow is not necessary, but reflow will incur repaint definitely.

to avid reflow and repaint as much as possible

  • use transform instead of positive and top
  • use visibility instead of display:none, the former will incur repaint while the latter will change layout
  • avoid access the property value of elements as much as possible, access offsetTop value will incur reflow

html

img responsive

1
2
3
4
5
6
7
<picture>
<source media="(max-width: 500px)" srcset="./img/420_tree.png">
<source media="(max-width: 1100px)" srcset="./img/1100_tree.png">
<img src="./img/420_tree.png">
</picture>

<img src="./img/420_tree.png" srcset="./img/420_tree.png 420w, ./img/tree.png 1100w" sizes="(max-width: 420px) 100vw, (max-width: 1100px) 100vw" class="tree">

get size and position of an element

SVG

properties

width/height: define the size in the document
viewBox: first two number are min-x and min-y used to define the position, the other two are define the scale relative to width/height

1
2
when the viewBox is same as width/height, then the dimension is 1. if it is smaller than width/height, then the dimension is larger than 1, and vice versa.
<svg viewBox="0 0 200 200" width="200" height="200" xmlns="http://www.w3.org/2000/svg"></svg>

path

M: move to

L: line to

H: draw a horizontal line

V: draw a vertical line

Z: close path, combine the start and the end

C: curve, x1 y1 x2 y2 x y, the last set x y specify where the line should end and the line start at the point where the last operation ended, the first two are control points.

1
2
3
4
 <svg className="selected-round-btm" viewBox="0 0 8 8" width="8" height="8" xmlns="http://www.w3.org/2000/svg">
<path d="M 0,8 L 8,8 L 8,0 C 8,0 8,8 0,8 " fill="#fff"></path>
<circle cx="0" cy="0" r="8" stroke="#e4e4e4" fill="none" />
</svg>

S: smooth curveto

A: rx ry x-axis-rotation large-arc-flag sweep-flag x y, draw an arc

  • rx ry radius x and radius y

  • large-arc-flag determines that the arc should be greater than or less than 180 degrees.

  • sweep-flag determines that the drawing direction is clockwise or anticlockwise.

  • x y the ending point calculated with angle, while the arc starting point is at three o’clock of a circle, circle center + radius = the arc starting point

    1
    2
    3
    4
    5
    6
    7
    8
    // get the ending point with an angle
    function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
    var angleInRadians = (angleInDegrees * Math.PI) / 180.0 // the length of the arc
    var x = centerX + radius * Math.cos(angleInRadians)
    var y = centerY + radius * Math.sin(angleInRadians)
    return [x, y]
    }
    polarToCartesian(9,9,9,45)

Q: x1 y1, x y, quadratic Bézier curve, to control the slope of two sides with one point, which is the first set
T: x y, smooth quadratic Bézier curveto, auto control the slope of two sides according to the last control point

filter

in && in2, SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint |
1.in is the first input, and in2 is the second input, while the placing order is same with the layer order of PS
2.if in is not existed, then the value will be the previous filter input

  • feBlend, to blend two layers ruled by a certain blending mode
    • in
    • in2
    • mode
  • feComposite, to combine two input images
    • in
    • in2
    • operator, compositing operations

CSS

stacking context

Special properties like z-index will cause elements to form a stacking context, as those properties can change the render order of elements on the page if their values are set to something other than none

position, opacity, filter, transform, detailed list of those special properties

tips

  • font linear-gradient
1
2
3
4
5
6
{
color: transparent;
-webkit-background-clip: text;
background-clip: text;
background-image: linear-gradient(130deg,red,black);
}
  • browsers (like chrome) can set a minimum fontsize which can’t be overthrew, but transform: scale can serve this problem.

    1
    2
    3
    4
    5
    6
    7
    8
      // set an unseen element for getting the minimum size
    const minimumSize = Number.parseInt(window.getComputedStyle(document.getElementById("minimumSize"), null).getPropertyValue("font-size").replace(/px/, ""))
    // generate different scales based on the minimumSize
    //the app has been set to fit `window.devicePixelRatio` in this situation. so the fontsize takes rem as unit, and item * fontSize is purposed to get the original size.
    const fontSizes = [1.2, 1.3, 1.4, 1.6, 2, 2.8].map((item) => {
    const _s = item * fontSize < minimumSize ? item * fontSize / minimumSize : 1
    return `--fontSize${item.toString().replace(/\./, "")}:${_s};`
    }).join("")
  • transform does work for inline elements

  • a problem may occur when use position: sticky with flex layout. the sticked elements may still moving when you scrolling.

    • i met this problem when i tried to make the first few columns fixed to left in a table component.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
      <!-- set flex's width to the sum total of all the cell widths 250vw to fix the problem -->
    <div class="container" style="overflow: auto">
    <div class="flex"style="display: flex">
    <div class="cell" style="width: 25vw;flex-shrink: 0;background: green; position: sticky; left: 0">cell</div>
    <div class="cell" style="width: 25vw;flex-shrink: 0;background: green;position: sticky; left: 25vw">cell</div>
    <div class="cell" style="width: 25vw;flex-shrink: 0;background: red">cell</div>
    <div class="cell" style="width: 25vw;flex-shrink: 0;background: red">cell</div>
    <div class="cell" style="width: 25vw;flex-shrink: 0;background: red">cell</div>
    <div class="cell" style="width: 25vw;flex-shrink: 0;background: red">cell</div>
    <div class="cell" style="width: 25vw;flex-shrink: 0;background: red">cell</div>
    <div class="cell" style="width: 25vw;flex-shrink: 0;background: red">cell</div>
    <div class="cell" style="width: 25vw;flex-shrink: 0;background: red">cell</div>
    <div class="cell" style="width: 25vw;flex-shrink: 0;background: red">cell</div>
    </div>
    </div>
    ````

    - text ellipsis
    - `text-overflow: ellipsis` only applies to single line

    ``` css
    .single {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    }
    • for multiple lines, either use after pseudo class to display “…” after the text, or cut off the text in js
  • 打印的每页带有表头: 包裹tr 标签, 让打印的每一页都带有表头

    1
    <thead style="display:table-header-group"></thead>

width setting

1
2
3
4
5
6
{
width: fill-available;
width: fit-content;
width: min-content;
width: max-content;
}

-webkit-box-reflect: right; reflect

vertical center

1
2
3
4
5
6
{
position: relative;
top: 50%; /* relative to the parent */
height: 50%;
transform: translate(0, -50%); /* relative to height */
}

attr()

1
2
3
4
/* get data with attr(), and needless for joining text with +*/
.test::before {
content: '我的内容是' attr(text) '颜色是' attr(data-color);
}
1
<div class="test" data-text="TEXT" data-color="red"></div>
1
htmlElement.dataset.text = “content”

shape-outside make the adjoining inline-elements around itself

CSS variable

1
2
3
4
5
6
7
8
:root { /* defining,it is not necessary to place in root*/
--size: 75px;
}
{
width: 500px; /* this one will be used by no-supporting browsers */
width: var(--size);
width: calc(var(--size) * 3);
}
1
2
3
var root = getComputedStyle(document.documentElement); // accessing
var cssVariable = root.getPropertyValue('--testMargin').trim(); // data getting
document.documentElement.style.setProperty('--testMargin', '100px'); // altering

pseudo-class

  • :before and :after are used to add elements, also float cleaning, and cannot used with img/select/input
  • :enabled and :disabled are used for customizing style of form according to status
  • :checked when checkbox or radio are chosen

selector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
p:first-of-type { }
p:last-of-type { }
/* nth-of-type and nth-child, the former according to the order of a given type, while the latter according to the order of children*/
p:nth-of-type(2) { }
p:nth-of-type(odd) { }
p:nth-of-type(even) { }
p:nth-of-type(3n) { }

/* select p which is behind h1*/
h1 + p { }

/*select all the children of container*/
.container > * { }

/* according to element's attributes */
input[type="button"] { }

unit

  • vw / vh / px
  • vmin / vmax 1% of viewport’s smaller/larger dimension.
  • em relative to the parent’s font-size
  • rem relative to Html font-size
  • fr represents a fraction of the available space in a grid container
  • lh / rlh Line height of the element / the root element..
  • ex x-height of element’s height
  • cap the normal height of capital letters
  • ch / ic average Average character advance of a full width glyph in the element’s font
  • lvh / svh, specified for the toolbar of mobile browsers

layout

  • 自适应: 多套代码根据用户代理提供不同版本的网页,在不同大小的设备上,网页以等比例的形式缩放宽度,呈现同样的主体内容和排版布局

  • 响应式: 一套代码,通过流式布局+弹性布局调整网页

  • 物理像素:计算机硬件,真实屏幕的像素点

  • css像素:属于逻辑像素的一种

  • 设备像素比(Device Pixel Ratio,DPR):物理像素与逻辑像素之比吗,比如iphone6物理像素是750 x1334,但实际逻辑像素是 375* 667,所以dpr = 2,这表示iphone6采用高清屏使用两个像素去渲染一个像素使画面更高清,iphone6 plus 甚至是dpr = 3

  • 1px 问题:设计师的视觉稿是相对于物理像素750px,实现一个1px边框,但css逻辑像素是375px,border-width:0.5px 使用transform: scale(0.5)

  • % + meta

  • vw/vh/% + px + flex layout,响应式布局

  • flex + vw/v/%h布局,局部使用px

  • 在跨设备类型的时候(pc <-> 手机 <-> 平板)使用媒体查询

  • rem ,响应式布局,动态设置 root 的 fontsize,子节点使用rem,和flexible不同的是可以根据pc、手机、平板的尺寸来设置比例使子节点计算方便

1
2
var deviceWidth = document.documentElement.clientWidth
deviceWidth = deviceWidth < 320 ? 320 : deviceWidth > 640 ? 640 : deviceWidth

flexible, self-adoption

模拟vw特性,动态的将页面宽度的1/10作为根节点的 fontsize,子节点使用rem就等于是按照页面比例计算

1
2
3
var doc = document.documentElement
var rem = doc.clientWidth / 10
doc.style.fontSize = rem + 'px'

高倍屏适配,修改了等比缩放视口的scale值,使得clientWidth变为物理像素尺寸,1物理像素等于1css像素,由原来的375=>750, media尺寸查询语句也同样需要修改

1
2
3
4
5
var metaEL = document.querySelector('meta[name="viewport"]')
var dpr = window.devicePixelRatio
var scale = 1 / dpr
metaEL.setAttribute('content', 'width=device-width, initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no')
document.documentElement.style.fontSize = deviceWidth / 7.5 + 'px' // 7.5并不固定

Storage

  • cookie, 4kb, can set the expire time, httpOnly = true means this cookie is server setting and only can be changed by server

    1
    2
    3
    document.cookie = "yummy_cookie=banana"
    document.cookie = "tasty_cookie=strawberry"
    console.log(document.cookie)
  • localStorage sessionStorage, maximum size 5MB

    1
    2
    3
    4
    localStorage.setItem('chooseId',JSON.stringify(this.$route.params))
    localStorage.removeItem('chooseId')
    localStorage.clear()
    localStorage.key(index)
  • indexedDB no size limits, it can do everything like a database does

  • caches, an object which include cache instances, each cache instance can viewed as a storage region. the return type of all the methods of caches or cache instance is promise.

    • methods which are mounted on caches are used for managing cache instances.

      • caches: keys open delete has match
      • differ between has and match: has return boolean while match give you the data
    • if we want to store something, then we need to use open to get a cache instance where is our data stay

      • cache instance: add addAll keys delete match matchAll put

        1
        2
        3
        4
        5
        6
        7
        8
        // differ between `add` and `put`: add can `fetch` and `store` the data automatically, but also because of automatically then we can't make changes on key and value to be stored
        // so fetch + put = add
        cache.add(request).then(function() {
        // request has been added to the cache
        });
        fetch(url).then(function(response) {
        return cache.put(url, response);
        })
      • when we use cache with service worker, the data we stored is the raw response returned by http

RegExp (regular expression)

1
2
var re = new RegExp(“a”, "img")
var re = /a/img;

modifier

  • i ignore uppercase and lowercase of letters
  • g global matching, to search from the start to the end whatever how much
  • m matching on multiple lines
  • es6 u turn on Unicode mode to deal with Unicode characters
  • es6 y similar with g, but it’s match work started form the beginning of the string
    • it’s effect is equal to add ^ at the beginning of a regexp, so it could regarded as a complement for that g couldn’t add ^
    • sticky, new property of RegExp, to know the regexp is added y or not

Properties

  • es6 regexp.flags, get all the modifiers

  • es6 regexp.source, get the regexp context

  • regexp.lastIndex, allow you to define and get the index from where the next match work started

    1
    2
    3
    4
    5
    const REGEX = /a/g;
    REGEX.lastIndex = 2; // to define the index
    const match = REGEX.exec('match a string');
    match.index // 6
    REGEX.lastIndex // 7, to get the index

test(), is matching or not

1
regExp.test(str) // boolean

search()

1
string.search(regExp) // return an index or -1

replace(), es6 replaceAll

1
string.replace(regExp, replaceText) // return the replaced string

exec()

1
regExp.exec(string) // return an array of information which include lastIndex, allow you to match along the last position.
1
2
3
4
5
6
// use with while
var regExp = /t(e)(st(\d?))/g;
var string = 'test1test2test3';
while (match = regExp.exec(string)) {
console.log(match)
}

with named capture groups(具名组匹配), you can get the data of each group which declared by ()

1
2
const regExp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
const matchObj = regExp.exec('1999-12-31');

match(), es6 matchAll

1
'For more information, see Chapter 3.4.5.1'.match( /see (chapter \d+(\.\d)*)/i) // return an array of information

symbols

PS Safari does not support ?!=n ?<=n ?<!=n ?:n

key usage
() Parentheses, to group regular expressions
[] match any character within the brackets
^ $ match from the start or the end of the string
[^a] match string which no ”a“
{n,m} the display times > n and < m
{n,} the display times > n
{,m} the display times < m
* equal to {0,}
+ equal to {1,}
? equal to {,1}, /.*?(\d)/, when ? is used with greed mode, it means to exclude a specific format
` `
. equal to {1,}
.* greedy mode
.*? the regex engine will, at every step it matches text into the “.” attempt to match whatever make come after the “.*?”
\d equal to [0-9]
\D equal to [^0-9]
\w equal to [a-zA-Z_]
\W equal to [^/w]
\s equal to [ \f\n\r\t\v](换页,enter,空格,tab,垂直制表符) , matching all the empty characters
\S equal to [^/s]
/S/s all the characters
(.|\n)* to match any characters across multiple line
?=n match string but don’t get, the string after which is n
?!=n match string but don’t get, the string after which isn’t n
?<=n (incompatible with safari) match string but don’t get, the string before which is n
?<!=n match string but don’t get, the string before which isn’t n
?:n match string but don’t get

examples

to match every character except ,;

1
/[^,;]+/

to match a string, stop matching until a specific format is encountered

1
2
3
 // ?(?=hello) match string but don't get
// ?(hello) match string and get
'"/public/images/index/组 4099.png","textAlign":"'.match(/public\/images\/(.*?(?="))/img)

verify float number, two standards judged by |

1
/^(([0-9]+\.?[0-9]+)|([0-9]*))$/.test("5.")

get an array of date number arranged by [year, month, day, hour, minute, second]

1
new Date().toLocaleString("zh").match(/[0-9]*/g).filter((el) => el).map(el => (el.length < 2 ? "0" : "") + el)
  • extract the type in the string returned by Object.prototype.toString.call
1
/(?<=\[object ).*(?=])/.exec(Object.prototype.toString.call({}))

Javascript

symbol and keyword

keyword function
=~ 按位非var num1=~25;//-26 值反一次再减一
Math.sqrt 根运算Math.sqrt(100) // 10
6%4 取余, c%2 !== 0
~~ 取整 ~~(6 / 4) // 1 ~~(9 / 4) // 2
&& 逻辑与
`
! 逻辑非
!! 反了之后再反一次
yield next yield* to stop or resume a generate function, yield* 加入另一个可迭代的对象
es6 ?. optional chain, stop running when null or undefined is encountered
es6 ?? null ?? 4; 4 ?? 5 the right value will be returned when the left value is null or undefined
es6 ?? null ?? 4; 4 ?? 5 the right value will be returned when the left value is null or undefined
es6 &&= a &&= 1 === a && (a=1) // if a is existed then assign 1 to it
es6 ??= a ??= 1 === a ?? (a=1) // if a is null or undefined then assign 1 to it
es6 ** 指数运算符 2 ** 3 // 8 b **= 3; // equal to b = b * b * b;
es6 symbol data type:designed to prevent the conflicts in property naming
  • delete obj.a delete an object’s own property but not those properties which is on the object’s prototype chin, return boolean

  • in: used to know whether a property exists in a object/array

    1
    2
    var arr = [1]; console.log(0 in arr); // true
    var arr = { a: 4 }; console.log('a' in arr); // true
  • es6 spread syntax: to expand an iterable such as an array expression or string

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // express rest arguments
    const bar = (...args) => args

    // to concat or insert items in an array/object
    { ...obj1, ...obj2 }
    [...iterableObj, '4', 'five', 6]

    // Applying with new operator
    new Date(...[1970, 0, 1])
  • while, the expression inside the brackets can be an assigning expression

    1
    2
    3
    4
    5
    6
     var bb = 1
    while ((aa = bb)) { // assigning the value of bb to aa, and judge aa is false or not
    console.log(aa)
    bb++
    if (bb === 5) bb = null // bb = null, then aa = null
    }
  • break continue return, break is used in switch/while/if/for to break a layer of the loop, only one layer

    1
    2
    3
    4
     for (let i = 0; i < 5; i++) {
    if (i === 3) continue
    console.log(i)
    }
  • es6 set whose members are similar with Array, but set will not have a repeated value

    1
    2
    3
    const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
    items.size // the length is 5, and the repeated value aren't be counted
    items.add(6) // add item
  • es6 map is similar with set, but the shape of map members is key: value like object. except the key of an object is always string, while the key of a map can be any type.

    1
    2
    3
    4
    5
    const m = new Map();
    const o = {p: 'Hello World'};
    m.set(o, 'content')
    m.get(o)
    m.size // 1
  • es6 WeakMap && WeakSet, all the properties of the two are shallow copied(weak reference), if an object are referenced only by WeakSet, then this object will be deleted by Garbage Collection

  • export && import && export default

variable declaration

var

  • if a var variable is not declared in a function scope, then it is a global object and is mounted on window

  • can be re-declared in a same scope

    1
    2
    3
    4
    5
    var b = 1
    var b = 1

    let c = 10
    let c = 20 // Identifier 'b' has already been declared
  • var variables can be used before declare, var declaration will be raising to the first line when engine is running, even a variable is declared in a if block

    1
    2
    3
    4
    console.log(a) // warning
    let a = 1
    console.log(b) // undefined
    var b = 1

let, const

  • let is used to declare a variable.
  • const is declare a constant whose assignment and declaration are simultaneously. value cannot be re-assigned. for a reference type data, value just keeps the memory location unchanged.
  • no variable increase
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (true) {
let m = 'block scope';
const n = 'block scope 2';
var k = 'global scope';
console.log(m); // block scope
console.log(n); // block scope 2
console.log(k); // global scope
}
console.log(m); // Reference Error
console.log(n); // Reference Error
console.log(k); // global scope

function a() {
var a = 1
if (a == 1) let a = 2
}
function a() {
let a = 1
if (a == 1) var a = 2 // warning
}
  • can’t declare a variable which’s name is same as function’s arguments
1
2
(function func(arg) { var arg })()
(function func(arg) { let arg })() // SyntaxError

Object

  • proxy

es6 shorthand

1
2
3
4
5
6
const a = {
'first word': 'hello',
[lastWord]: 'world'
}

const baz = {foo}

iterate

  • for...in... iterate object’s key and array’s index
  • forEach can’t jump out by return, forEach for...of... iterate value and can’t be used on Object
1
2
3
4
5
Object.keys(obj) // obj's attribute names except Symbol, inherited and non-enumerable attributes
Object.getOwnPropertyNames(obj) // obj's attribute names, include inherited and non-enumerable attributes, but not Symbol
Object.getOwnPropertySymbols(obj) // only Symbol
Reflect.ownKeys(obj) // all the attribute names no except
for (let i in obj) console.log(obj[i])

Instance’s Properties

1
2
3
4
5
6
7
8
obj.hasOwnProperty()
// `hasOwnProperty` which placed on an object instance can be replaced
// Object.create(null) will create an object that does not inherit from Object.prototype, making those methods inaccessible.
Object.create(null).hasOwnProperty("foo") // Uncaught TypeError: Object.create(...).hasOwnProperty is not a function

// the follow two are worked same
Object.hasOwn({a:0},"a")
Object.prototype.hasOwnProperty.call({a:0}, "a")

Object’s Properties

  • es6 Object.values({}) Object.keys({})

  • es6 Object.assign(), copy the properties of the arguments to the first argument

  • es6 Object.entries({}) Object.fromEntries([]) transform object to array and vice visa

    1
    2
    3
    const obj = {a: 'someString', b: 42}
    Object.entries(obj) // [['a', 'someString'], ['b', 42]]
    Object.fromEntries(Object.entries(obj)) // {a: 'someString', b: 42}
  • es6 Object.is(value1, value2) compare whether two values are same, can compare objects by comparing they reference. almost same as ===, but there has two differences:

    1
    2
    3
    4
    5
    +0 === -0 //true
    NaN === NaN // false

    Object.is(+0, -0) // false
    Object.is(NaN, NaN) // true
  • Object.prototype.toString.call() get data’s type

  • es6 Object.getOwnPropertyDescriptors

  • es6 Object.setPrototypeOf() Object.getPrototypeOf() set and get the prototype of an object

JSON

  • JSON.parse(string)

  • JSON.stringify(obj)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    JSON.stringify(object: any, replacer: (key: string, value: any) => any, space: string)
    const foo = {
    foundation: "Mozilla",
    model: "box",
    week: 45,
    transport: "car",
    month: 7,
    obj: {
    a: 2,
    b:[7,8]
    }
    };

    // if replacer is a function, replacer will be called on each value to-string process
    // ps: the value of the first call is the target object
    JSON.stringify(foo, (key, value) => {
    console.log(key, value)
    if (typeof value === "number") {
    return "number"
    }
    return value
    }) // '{"foundation":"Mozilla","model":"box","week":"number","transport":"car"}'

    // if replacer is an array and all the items are string, the resulting string will only keeps the {key: value} which's key is listed in the replacer
    JSON.stringify(foo, ["month", "obj", "a"]); //'{"month":7,"obj":{"a":2}}'

Array

  • includes(item), item exists or not

  • lastIndexOf, indexOf return index

  • at(index), index can be negative, return item of the given index

    1
    2
    3
    const arr = [1, 2, 3, 4, 5];
    arr.at(2) // 2
    arr.at(-2) // 4
  • forEach no return and cannot break the loop
    if an item is deleted by shift() or any other methods during the loop, the items after it will be skipped

  • every all items return true => return true, any one return false => return false and break the loop

  • some any item return true => true, no one return true => false

  • find findLast | findIndex | findLastIndex any item return true => return the item or index(findLast return the last one),IE 11 doesn’t support

  • filter return an array constituted by items which is returned true

  • map return an array constituted by the return data of the function

  • reduce reduceRight, get an accumulation from an array, the latter is executed by the order of right to left

1
[1,2,3].reduce((accumulator, currentValue, currentIndex, Array) => accumulator + currentValue)
  • reverse reverse the order of an array

  • join

  • fill(value, start, end)

  • pop / shift remove the first / last item of an array, and return the removed item

  • unshift / push add item to the start / end of an array, and return the current length of an array

  • splice slice, three parameters: start index, delete count, items which need to add. return the removed items

    • splice changes the original array, while slice create new one
  • concat concat two or more arrays, and return a new array. the items of new array are shallow copied

  • sort

  • flat

    1
    2
    3
    4
    // 数组降维,递归地将数组展平到指定的深度,默认为1	const array = [1, [2, [3]]];
    array.flat();  // → [1, 2, [3]]
    array.flat(Infinity);   // → [1, 2, 3]
    [234].flatMap((x) => [x, x * 2]);  // → [2, 4, 3, 6, 4, 8]
  • set

    • has(value) => boolean, value exists or not
    • add(value) return the array itself
    • delete(value) boolean, delete one item
    • clear() no return, clean all items
    • transfer between array and set
    1
    2
    [...new Set(array)]	// from array to set, and this will delete repeated items
    Array.from(new Set(array)) // set translate to array

scope

scope types

  • global scope
    1. defined at the external of the outmost function
    2. declared without keyword var, let and const
    3. belonging to window

ES6 Module scope

1
2
3
4
5
6
7
// lib.js
var a = "a";
export var b = "b";
// main.js
import {b} from "lib";
console.log(a); // error
console.log(b); // "b"

function or local scope

a variable is declared within a function, so it can’t be accessed from the outside.

block scope

if / switch / while / for create a block scope. a variable which is defined by let / const

static scope

when looking a variable, the engine will go to the scope in which the variable was created

1
2
3
4
5
6
7
var x = 10
function fn() { console.log(x); }
function show(f) {
var x = 20;
fn() //10
}
show(fn);

nested scope

a scope can be nested inside another scope.

scope chain

when the JavaScript engine try to find a variable, first it will seek in the current scope, if there is no result then it will go to the parent’s scope. finding layer by layer, that is scope chain.

1
2
3
4
5
6
7
8
9
var a = 100
function F1() {
var b = 200;
(function () {
var c = 300
console.log(a, b, c)
})()
}
F1()

garbage collection

FinalizationRegistry listen to the garbage-collect event

FinalizationRegistry

to register an obj and invoke a callback after the obj is garbage-collected

1
2
3
4
5
const registry = new FinalizationRegistry(heldValue => {
console.log(heldValue)
});
let obj = { a: 0 }
registry.register(obj, "some value"); // target and holdings cannot be same

Stale closure

The stale closure captures variables whose value is outdated

  • createIncrement function returns two functions, increment and log. The former responsible for value increasing. the latter logs a const, whose value is fixed since it defined, then every time call the log fun, it gets message which is a fixed value.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function createIncrement(incBy) {
let value = 0;
function increment() {
value += incBy;
console.log(value);
}
const message = `Current value is ${value}`;
function log() {
console.log(message);
}
return [increment, log];
}
const [increment, log] = createIncrement(1);
increment(); // 1
increment(); // 2
log(); // Current value is 0
  • when use setTimeOut and setInterval, in which the function delay to execute, but every variable that the fun got is the current value at the time of the fun defined, that is to say if the variables get changed during the delay time, then the fun only get the old variables.

prototype

  • every object has a prototype, from which the object can inherit properties and methods

  • an instance inherits prototype from constructor, which is placed on the __proto__

  • a constructor has a prototype which has two properties constructor and **proto**, besides it has proto property which is inherited from Object.prototype

    • the former, the prototype.constructor refer to the default constructor
    • the latter, even all the built-in functions such as Object, Function, Array、RegExp、Date、Boolean、Number、String , the prototype.proto of them point to the Object.prototype, that means they inherited from Object, and Object.prototype.proto refer to null.
1
2
3
Person.prototype.constructor === Person // Person is a constructor, Person.prototype.constructor point to the "constructor" function self
person01.__proto__ == Person.prototype // person01 is an instance, person01.__proto__ point to a place same as Person.prototype
Array.prototype.__proto__ == Object.prototype == Object.prototype.__proto__ = null

property chain

when we access the property of an object, first the engine will try to find the property in the object, if it doesn’t find, then it will look at the object.__proto__, if it still doesn’t find , then look at the object.__proto__.__proto__,…. at the end of the prototype chain of __proto__, the engine will find the Object.prototype, in which the prototype is null, then the engine will be sure that the property doesn’t exist.

diff between constructor and normal function

  • a constructor usually doesn’t use return keyword, because this of a constructor will be used as the result of new keyword.
  • when the returned result from a constructor is an Object, then the result will be used as the result returned by new keyword. otherwise, if the result is primitive type, then this will be as the result of new keyword.
  • by the first rule, this and new are used in a constructor but not in a normal function

what does NEW do?

  • create an Object
  • bind this of the current scope to the object
  • copy the prototype from the constructor, and placed it in the object._proto_
  • execute the code inside the constructor, and return the object

Inheritance

  • create a child object classes which will inherit features from another class
  • OO => object oriented programming
  • favor object composition over inheritance
  • concatenative inheritance, inherit features from another object by copying the source objects properties
    • Object.assign()
    • … spread syntax
    • bind, call and apply(can receive an array). binding “this” to a function
1
2
3
4
5
6
7
8
9
10
11
12
let beBound = { a: 1 }
let beCalled = function (...arg) { console.log(this, arg )}
// the first argument will be bound with the function, the others used as rest arguments
// return a function which are created by binding a copy of the first argument to the called function
let newOneFixedArgument = beCalled.bind(beBound, "newOne", "fixedArgument")
newOneFixedArgument()
let newOneFreeArgument = beCalled.bind(beBound)
newOneFreeArgument("newOne", "freeArgument")

// call and apply will execute the function immediately, and doesn't change the called function
beCalled.call(beBound, "call", "individual arguments")
beCalled.apply(beBound, ["apply", "array argument"]) // accept an array

prototype delegation

  • new constructor
    • functional inheritance / factory function. it is not a constructor or class. it works by producing an object from a factory, and extending the produced object by assigning properties to it with concatenative inheritance.
  • class extend / sub-classing.
    inherit everything from a class, can’t choose what you wanted
    this initialization by calling the parent’s constructor with super() and can pass arguments to the parent, while in the constructor function that the new keyword does the initialization automatically.

differ between vue and react

  • Vue
    • focus on view, that made dom operations more flexible and productive
    • when you have some public functions, you can’t import those function in template tag, you also have to write script tag
  • React
    • more suitable in a complex project
    • to render html by jsx
    • below diffs are also the diff between class component and function component
    • no this issues in function components, you don’t have to do scope bonding, when you inherit someone’s code, if you don’t search, you don’t even know what this have
    • code lesser with function component, but worse maintaining
    • doesn’t need to manage state and life cycle

Architectures

mvc

  • Model - View - Controller
  • model is not only contains data model, also describes how the data can be changed and manipulated.
  • view is the UI components which is rendered by the data from the controller.
  • controller sits between model and view, like a mediator processing the data from the model and passing back to the view for rendering.
  • view and model can interact with each other directly, so it’s coupled.

MVVM

  • Model – View – ViewModel
  • view is same with the MVC's view
  • model stores data and related logic, rec
  • like mvc, ViewModel sits between model and view. but it accepts user’s data from view and the data from model, and interacts with view and model.
  • view and model can’t interact with each other, it’s decoupled.

mvp

  • model - view - presenter
  • mvp is derived from mvc. it’s decoupled, means view and model can’t talk to each other.

active view and passive view

  • the later only outputs UI and doesn’t accept user’s input, contains zero logic
  • the former contains events, data binging, and behaviors

closure

closure is a combination created by binding a function to the lexical environment. it allow you to access the outside scope from the inner of the function.

  • data privacy. it means that you can’t access the data of the inner scope from the outside.
  • privileged methods. the methods exposed by the function are privileged, because they can access the arguments of the inner scope and the outside.
  • stateful function. a state is a snapshot of the current environment, every change will take a picture of the current environment.
1
2
3
4
5
6
7
8
9
var func = () => {
let a = 3
return (b) => {
a = ++ a
return b * a
}
}
let closure = func()
closure(4) // 12
  • partial application. it takes advantage of closure scope in order to fix parameters.
1
2
3
4
5
const partialApply = (fn, ...fixedArgs) => {
return function (...remainingArgs) {
return fn.apply(this, fixedArgs.concat(remainingArgs))
}
}

deep and shallow copy

  • basic data types: data are stored in stack

  • reference data types: data are stored in heap, while stack only have the reference of object

  • shallow copy: only copy the reference of object

  • deep copy: copy data

the following methods can deep copy but only the first layer of an object.

1
2
3
4
Object.assign({}, state)
{...state}
Array.prototype.concat()
Array.prototype.slice()

completely deep copy

  • structuredClone creates a deep clone of a given value

  • JSON.parse(JSON.stringify()), some complex types will be translated into string:

    • Dates, functions, undefined, Infinity, RegExps, Maps, Sets, Blobs, FileLists, ImageData, sparse Arrays, Typed Arrays

    • undefined will be ignored

    • an object in which some properties are refer to each other can’t be converted

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      let obj = {
      a: 1,
      b: {
      c: 2,
      d: 3,
      },
      f: undefined,
      }
      obj.c = obj.b
      obj.e = obj.a
      obj.b.c = obj.c
      obj.b.d = obj.b
  • MessageChannel, data that is delivered MessageChannel are deep copied. but delivering a function will cause an error

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     function deepCopy(obj) {
    return new Promise((resolve) => {
    const { port1, port2 } = new MessageChannel()
    port2.onmessage = (ev) => resolve(ev.data)
    port1.postMessage(obj)
    })
    }

    deepCopy(obj).then((copy) => {
    console.log(copy);
    })

event loop

  • Heap and Stack?

    • the former is where objects in, the latter in where functions are waiting to execute.
  • synchronous and asynchronous

    • they are two kinds of js tasks. the former constitutes execution context stack(执行栈) in the Main-Thread, the latter are in the Task Queue.
  • Event Loop

    • after all the tasks of Task Queue are done, the engine will constantly reading task queue and trying to find tasks that can be end waiting status. the engine will push it into stack once it finds tasks. the process that JavaScript engine constantly finding tasks is called Event Loop.
  • Call Stack

    • every call of function will leave a Call Frame(调用帧), which keeps the inner information about function including variables and the location where the function called, those information will be deleted after the function is completed.
    1
    2
    3
    4
    5
    // put C into stack => B in => A in => A out => B out => C out
    function funA() { console.log('funA') };
    function funB() { funA() }
    function funC() { funB() }
    funC()
  • Task queue have been divided into two types Macro and Micro

    • the former including setImmediate / setTimeout / setInterval / MessageChannel /requestAnimationFrame / UI render/ I/O in node.js, while the later including the onerror and then callback of Promise.

    • setImmediate -> MessageChannel -> setTimeout 0

    • usually the engine will check the MacroTask first and the MicroTask second. however, there has an important point that Promise initialize and resolve are synchronous.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
       setTimeout(function () {
      console.log(1)
      }, 0)
      var p1 = new Promise(function (resolve, reject) {
      console.log(2)
      setTimeout(function () {
      console.log(4)
      resolve(1)
      }, 0)
      })
      setTimeout(function () {
      console.log(3)
      }, 0)
      for (var i = 0; i < 5; i++) {
      ;(function (j) {
      p1.then(function (value) {
      console.log("promise then - " + j)
      })
      })(i)
      }
  • async await, look at the following example:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    async function async1(){
    console.log('async1 start')
    await async2()
    console.log('async1 end')
    }
    async function async2(){
    console.log('async2')
    }
    console.log('script start')
    setTimeout(function(){
    console.log('setTimeout')
    },0)
    async1();
    new Promise(function(resolve){
    console.log('promise1')
    resolve();
    }).then(function(){
    console.log('promise2')
    })
    console.log('script end')
    • async1() doesn’t have await prefix, async1 will be translated by v8 like:

      1
      2
      3
      4
      5
      6
      7
      // async2 will execute immediately, the code after `async` will be put in `then` callback
      function async1(){
      console.log('async1 start')
      Promise.resolve(async2).then(()=>{
      console.log('async1 end')
      })
      }
  • Tail Call means to call another function at the end of a function’s operation.

    1
    function a(x) { return b(x) }
    • b is a Tail Call. from Call Stack, we know that the fun will keeps it’s inner info until its operation is completed. while Tail Call is the final step of fun, the fun is completed after called Tail Call, then the Call Frame of fun is no longer kept.
    • this will save a great memory, also called Tail call optimization.
  • Tail Recursion

    • at the reason of call frame, that Recursion often takes a lot of memory and cause stack overflow, for optimization we can use Tail Recursion.

      1
      2
      3
      4
      5
      6
      7
      8
      function factorial(n) {
      if (n === 1) return 1;
      return n * factorial(n - 1);
      }
      function factorial(n, total) {
      if (n === 1) return total;
      return factorial(n - 1, n * total);
      }

debounce and throttle

  • debounce. a function can be executed when it is not called during a specific time

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // execute debounce => got a function which bound with the debounce scope
    // every time the instance executed that will clean and reassign the timer
    const debounce = (func, delay) => {
        let timer
        return function ({
            const context = this, args = arguments
            clearTimeout(timer) // to clean before reassign
            timer = setTimeout(() => func.apply(context, args), delay)
        }
    }
    const instance = debounce(function (console.log("executing") }, 3000)
  • throttle. a function can be executed only when the time is up

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
      // execute throttle => got a function which bound with the throttle scope
    //when the isExpired is true, that means that the function can be executed and when it executed, then change the isExpired's state to false and set a time to change back
      const throttle = (func, delay) => {
            let isExpired = true
            return function ({
                const context = this
                const args = arguments
                if (isExpired === falsereturn
                func.apply(context, args)
                isExpired = false
                setTimeout(() => isExpired = true, delay)
            }
        }
        const instance = throttle(function (console.log("executing") }, 3000)

breakpoint resume

web: fileReader + slice + FormData
server: createWriteStream + createReadStream

messageChannel

  • to communicate between two iframes / web workers / js modules
  • deep copy

generator

  • use generator to simulate async function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function run(fn: any) {
const gen = fn()
function thunk(...argu: any[]) {
const res = gen.next(...argu)
if (res.done) return
if (res.value instanceof Promise) {
res.value.then((res: any) => thunk(res))
}
}
thunk()
}

const gen = function* (): Generator<any, any> {
const a = yield get({ api: "manifest.json", params: { tenant: "devices" }, options: { sync: false } })
console.log("a", a)

const b = yield get({
api: "manifest.json",
params: { tenant: "devices" },
options: {
sync: false,
},
})
console.log(b)

}

run(gen)

Typescript

references

setting tsconfig for specific file

diff with js

==pro:==

  • object-orient language
  • static type checking. it can find low level bugs, like spelling mistake, incorrect or instanceof variable properties
  • type infer.
  • optional parameters
  • enum support
  • better support in IDE, like intelliSense of editor, auto-supplement
  • the type files can increase code reading ability, and make the project maintaining easer
  • .d.ts can be viewed as specifications
  • to identify incompatible interfaces when the field name changed

==con==

  • compiling step is required, and it may take a long time.
  • abstract classes is not support
  • definition files for a third library is required
  • pollutes the code with type gymnastics

type judgement

  • Generics

  • keyof

  • typeof

  • indexed access: User["name]

  • map types, use - or + to remove readonly or optional modifier

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    type OptionsFlags<Type> = {
    [Property in keyof Type]: Type[Property]
    }
    // change all readonly or optional properties to normal
    type CreateMutable<Type> = {
    -readonly [Property in keyof Type]: Type[Property];
    };
    type Concrete<Type> = {
    [Property in keyof Type]-?: Type[Property];
    };

Diff of null and undefined

  • null means an absence of value
  • undefined means not initialized

Diff of .ts and .d.ts

  • .d.ts file is a declaration file, and would not be complied as a js file
    • in a .d.ts file, if we want it act as a global declaration, then we have to use /// Triple-Slash Directives to import dependencies
    • /// <reference types="node" /> is used for importing an outside module, while /// <reference types="./global.d.ts" /> is for importing a local declaration file

Diff of type and interface

  • type is used to declare a type alias, act like a variable. while interface introduce a named object type.

    1
    2
    3
    // get the type of a variable to deduct (a part) of a payment from (the total)
    let div = document.createElement("div")
    type B = typeof div
  • Adding new fields to an existing interface, but a type cannot be changed after being created

    1
    2
    3
    4
    5
    6
    7
    8
    interface User {
    name: string;
    age: number;
    }
    interface User {
    sex: string;
    }
    /* { name: string; age: number; sex: string } */

features

  • circular references

    1
    2
    interface LocalRes<T> { [x: string]: T }
    type LocalResPackage = LocalRes<LocalResPackage | string>
  • new describe the shape of a constructor

  • abstract to mark a class with abstract, means that the class is only meant to be extended from, can’t be used directly

    1
    2
    3
    4
    5
    6
    7
    8
    abstract class Shape {
    abstract getArea(): number;
    }

    new Shape(); // error Cannot create an instance of an abstract class.

    class Square extends Shape {}
    new Square(3) // right
  • extends conditional types
    SomeType extends OtherType ? TrueType : FalseType;

    1
    2
    3
    // if Dog extends from Animal, then Example = number, otherwise Example = string
    type Example = Dog extends Animal ? number : string;

  • infer
    can be used to unpack type, to get the item’s type of an array, the return value’s type or the parameter’s type of a function

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // if T is a function ? the return value of the function : any
    type Unpack<T> = T extends (...args: any[]) => infer R ? R : any;

    // if T is an Array ? R : T
    type Unpack<T> = T extends Array<infer R> ? R : T

    // if R is Reducer ? Reducer's first parameter S : never
    type ReducerState<R extends Reducer<any, any>> = R extends Reducer<infer S, any> ? S : never;
    type Reducer<S, A> = (prevState: S, action: A) => S;

    // get the parameter type of a constructor
    abstract class AbstractClass {
    constructor(a: string, b: number) { }
    }
    export type InferAbstract<T> = T extends abstract new (...args: infer Args) => infer _ ? Args : never; // new a function which return a value, infer the parameter as Args, mark the value as abstract class, if T is a abstract class ? Args : never
    type Result = InferAbstract<typeof AbstractClass> // [a: string, b: number]

  • decorators, use the form @expression, where the expression must infer to a function.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     function first() {
    console.log("first(): factory evaluated");
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("first(): called");
    };
    }

    function second() {
    console.log("second(): factory evaluated");
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("second(): called");
    };
    }

    class ExampleClass {
    @first()
    @second()
    method() {}
    }
  • Record

    1
    2
    3
    4
    5
    6
     type AnyObject = Record<string, any>
    type Coord = Record<"x" | "y", number>
    type Coord = {
    x: number,
    y: number,e
    }
  • Readonly Partial Required: all the properties are Readonly or selectable or required

    1
    2
    3
    4
    5
    type Coord = Partial<Record<"x" | "y", number>>
    type Coord = {
    x?: number,
    y?: number,
    }
  • Pick omit: to pick or omit some properties from a given type

    1
    2
    3
    type Coord = Record<"x" | "y", number>
    type CoordX = Pick<Coord, "x">
    type CoordX = Omit<Coord, "x">
  • ReturnType Parameters, the former is used for getting the output of a function, while the later is used for a function’s input

    1
    2
    let timer: ReturnType<typeof setTimeout>
    Parameters<(props: Event) => void>
  • typeof

    1
    2
    const zed: Hero = { name: "影流之主", skill: "影子" };
    type LOL = typeof zed; // type LOL = Hero
  • keyof collecting key

    1
    2
    3
    4
    interface Person { name: string; age: number;  location: string; }
    type K1 = keyof Person; // "name" | "age" | "location"
    type K2 = keyof Person[]; // number | "length" | "push"|"concat" | ...
    type K3 = keyof { [x: string]: Person }; // string | number
  • enums

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    enum Themes {
    default = "_default",
    thinkuem = "_thinkuem",
    safeuem = "_safeuem",
    }
    // collect all the values of an enum, but the types of all the values will be inferred as string, even some values are number or string
    type ThemesVal = `${Themes}`
    // generate a interface
    type ThemesVal = Record<Themes, string>
    // collect all the keys of a enum
    type ThemesVal = keyof typeof Themes
  • template literal type,a set of every possible string literal that could be represented by each union member

    1
    2
    3
    type a = 1 | 2 | 3
    type b = 4 | 5 | 6
    type ab = `${a}_${b}` // "1_4" | "1_5" | "1_6" | "2_4" | "2_5" | "2_6" | "3_4" | "3_5" | "3_6"
  • template literal has four convenient features Uppercase Lowercase Capitalize Uncapitalize

    1
    2
    3
    type PropEventSource<Type> = {
    on(eventName: `${string & keyof Type}Changed`, callback: (newValue: any) => void): void;
    };
  • type assertion, as or <> syntax

    1
    2
    3
    let value: unknown = "Foo";
    let len: number = (value as string).length;
    let len: number = (<string>value).length;
  • is

    1
    2
    3
    export function foo(arg: string): arg is MyType {
    return ...
    }
  • in

    1
    console.log('model' in car);  // boolean
  • this

    1
    2
    3
    4
    5
    6
    7
     class Box<T> {
    value?: T;

    hasValue(): this is { value: T } {
    return this.value !== undefined;
    }
    }
  • as const

    1
    2
    3
    4
    5
    6
    let x = [0, 1] as const; // let x: [0,1]
    // another write pattern: let x = <const>[0, 1];
    let x = [0,1] // let x: number[]

    let y = [10, 20] as const; // Type 'readonly [10, 20]'
    let z = { text: "hello" } as const; // Type '{ readonly text: "hello" }'
  • any extends object instead of any when reference to an object

  • void is used when a function’s output is null or undefined, if a fun does not use return keyword then its value is undefined

  • unknown is a type-safe of any type. you can narrow down unknow to any type by type assertion

  • never is used when a function can’t end which means it can’t return a value even an undefined. to express an empty object

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function get<T extends object, K extends keyof T>(o: T, name: K): T[K] {
    return o[name]
    }
    let foo: unknown = "hello";
    let bar: string = foo as string;

    function login(data: LoginForm): void {}

    function login(data: LoginForm): never {
    while (true) {}
    }
    function login(data: LoginForm): never {
    throw new Error("error");
    }

    type EmptyObject = Record<string, never>
  • map types, to generate a type According to a map object, and can be a generics

    1
    2
    3
     type OptionsFlags<Type> = {
    [Property in keyof Type]: boolean;
    };
  • index access for looking up a specific property of a type

    1
    type Age = Person["age"]
  • generics generate a type with a specific params

    1
    2
    3
    4
     function identity<T>(arg: T): T {
    return arg
    }
    let myIdentity: <Type>(arg: Type) => Type = identity
  • implements, to check that whether a class is satisfied the contract specified by one or above interfaces

    1
    2
    3
    4
    5
    6
    7
    8
    9
     interface Runnable {
    run(): void;
    }

    class Job implements Runnable {
    run() {
    console.log("running the scheduled job!");
    }
    }
  • triple slash directives, to introduce other files in the compiling process

    1
    /// <reference path="..." />
  • class modifiers

    • public
    • protected: All the members of the class and its child classes can access them, But not the instance of the class.
    • private: Only the members of the class can access them.

useful tricks

  • reduce method needs to provide the initial type and the return type when the return type is not same with the type of array item

    1
    reduce< [string, Lan], { [k: string]: Lan }>((a, c) => {})
  • refer to React component

    1
    2
    new() => React.Component<any, any>
    typeof React.Component
  • promise type, the argument’s type of resolve is number, while the argument’s type of reject is infer to any

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
      function test(arg: string): Promise<number> {
    return new Promise<number>((resolve, reject) => {
    arg === "a" ? resolve(1) : reject("1");
    });
    }

    - the resolve type of promise

    ``` js
    type resolve = Awaited<ReturnType<typeof drawSlogan>>
  • to override a property of a interface extended

    1
    2
    3
    interface ColorPickerProps extends Omit<BasicProps<string>, "change"> {
    change: import("react-color").ColorChangeHandler
    }
  • use map and literal to create new property names

    1
    2
    3
    type Getters<Type> = {
    [Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
    };
  • to extend html attributes

    1
    2
    3
    4
    5
    declare module "react" {
    interface DOMAttributes<T> {
    name?: string
    }
    }

React

life cycle

  • Mount Stage

    • initialize

      • constructor
      • inside the function
    • before render

      • getDerivedStateFromProps, have the new props and ready to change state

      • inside the function to compare the state and then return what you want

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        function ScrollView({row}) {
        const [isScrollingDown, setIsScrollingDown] = useState(false);
        const [prevRow, setPrevRow] = useState(null);

        if (row !== prevRow) {
        // Row 自上次渲染以来发生过改变。更新 isScrollingDown。
        setIsScrollingDown(prevRow !== null && row > prevRow);
        setPrevRow(row);
        }

        return `Scrolling down: ${isScrollingDown}`;
        }
    • render

    • after render

      • componentDidMount, http request should be send
      • useEffect
  • update stage

    • getDerivedStateFromProps

    • shouldComponentUpdate

      • use useMemo to shallowly compare
      1
      2
      3
      const Button = React.memo((props) => {
      // 你的组件
      });
    • render

    • getSnapshotBeforeUpdate(1.contain state before update and after update,2.used to comparative calculations,3. in the end, it could return a value as the third argument of - DidUpdate)

      • for getting the old and new state, by useRef
    • componentDidUpdate

  • unmount stage

    • componentWillUnmount
    • the return function of useEffect()

change view

  • setState() of class component
    • even an empty object like this.setState({}) will also trigger a new update cycle
    • not a async method
    • when we call a setState, multiple calls of setState will be merged to one call, so the data will not update immediately. we can use callback to get the updated data.
    • we can use setTimeout or native events to step over React setting, to achieve a sync response.
1
2
3
4
5
6
7
8
9
componentDidMount(){
setTimeout(() => {
this.setState({ number: 3 })
console.log(this.state.number) // 3
}, 0)
}
componentDidMount() {
document.body.addEventListener('click', this.changeVal, false)
}
  • useState() useReducer() hook of function component
  • context, this is shallowly compare
  • use ref to change dom
  • forceUpdate(), only support in class component and it will skip shouldComponentUpdate()
  • dispatch() in redux
  • native dom handlers

components conversation

  • parent to children: props
  • children to parent:callbacks inside the parent props
  • between brother: find the common parent node, through the parent by the above methods
  • cross layer: by context
  • redux

Reconciliation algorithm

it is used to diff one tree with another to determine which parts need to be changed. also called differ algorithm

key

when an array re-rendering, React will check each list item according to the last render. if an inexistent item of the last render is found in the current render, then react will create an new element. if an item of the last render is altered in the current render, then react will delete the old one and create a new one.

if we use index as key, the key will be changed as the array’s order changed

high order component

  • HOC is a function, accepts a component and other arguments, return a new component which should keep similar interface with the original one.
  • HOC’s name begins with with, like withButton
1
type HOC = (component: React.component, props) => React.component

features

  • it totally control the component, and add new features to it, like make the name of the data props.
  • it can unify data source, inform the component to change when the data of data-center change.
  • it render different components based on status like after login, therefore it could avoid to set multiple routers.
  • when a function needed in multiple components. a different way from importing the function in different components is to apply the function to > different components in HOC.
  • if you want to change the component received in HOC, the better way is to return a composition of a new component and the component received, > rather than to change the component received directly.
  • container and component. the former deals with data and props, the later receive props form container and only responsible for rendering.

Render Props

  • it is a mode, a component with a callback which accepts component’s data and return React elements
  • tips: try not use Render Props with pureComponent, because this callback will return a new value after parent re-render. while pureComponent is shadow compare for reduce the times of children re-render, but with Render Props the result of compare will always be false.
1
2
3
4
5
6
7
<DataProvider render={data => (
<h1>Hello {data.target}</h1>
)}/>

const DataProvider = (props) =>{
return <div>{this.props.render(this.state)}</div>
}
  • render prop is kind of a simply HOC
1
<Mouse render={mouse => <Component {...this.props} mouse={mouse} />}/>

ref

info

  • ref is a way for accessing dom
  • create ref by React.createRef() and useRef() hook
  • it is not support to access ref directly on a function component which does not have ref instance.

callback ref

  • differ from React.createRef(), pass a function to components is also allowed
  • a better way is use with useCallback() hook, then it wouldn’t be executed every time after component updated
1
2
3
4
5
6
7
8
const inputRef = (node) => {
// argument is a dom element during mount
// argument is null when unmount
}
const inputRef = useCallback(node => {
console.log(node);
}, []);
<input type="text" ref={inputRef}/>

ref forwarding

  • Ref forwarding lets components opt into exposing any child component’s ref as their own.
  • we can customize the data that the component exposes to the outside using useImperativeHandle() hook.
  • to access child node from a parent component for triggering focus or measuring the size or position of a child dom.
  • it is useful in High Order Component, like assigning ref to input’s ref in a input component
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function FancyInput(props, ref) {
const inputRef = useRef();
// assign focus to inputRef
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <div><input ref={inputRef}/></div>
}
FancyInput = forwardRef(FancyInput);

// this ref will be the input's ref and can use the focus method
const ref = React.createRef();
<FancyInput ref={ref} />;

hook

  • each component has an initial list of “memory cells”, when we call a hook like useState(), it reads the current cell or initializes it during the first render.
  • hook is a function which lets you to “hook into” React state and lifecycle features from function components.
  • use pure function as much as possible
    optimization: when we need to set an initial value of a hook returned by a function, compare to pass the function directly as an argument to a hook, a more optimized writing pattern is to set an arrow function that returns the desired function.
1
2
3
4
// fun will only execute once when the component initialize
const [goodGet, goodSet] = React.useState(() => fun(0))
// fun will execute every time the component re-render
const [badGet, badSet] = React.useState(fun(1))
  • useState() keeps the local state in a function component, when we update a state variable, react replaces the state instead of merging it like this.state() in class component.

  • useReducer() is used to store a complicated state, act like a small redux in a component.

  • a best solution for passing callbacks to children is to use useContext() together with useReducer(). with this, we don’t have to pass callbacks layer by layer.

    • create a context object for passing dispatch to children, so any child within the component can get the dispatch by useContext.
  • useRef() is used to store data, and the value returned by it will be valid in the whole life cycle

  • useEffect() and useLayoutEffect() the former invoked after the data id updated, while the later is called after the DOM is updated

1
2
3
4
5
6
7
8
useEffect(() => {
// mounted = componentDidMount and componentDidUpdate
return fun() // unmount = componentWillUnmount
}, [])
useEffect(() => {
// updated
return fun()// before update and unmount = componentWillUnmount and componentWillUpdate
}, [id])
  • useContext() accept a context object created by createContext() and returns the current context value.. it’s used when components of different nesting levels need to access the same data.

    1
    const value = useContext(MyContext)
    • createContext() accept a default value and returned a context object which has three properties. context will shallowly compare the properties of value to decide whether it should re-render.
    1
    const MyContext = React.createContext(defaultValue)
    • provider: a react component, that allows to consume components to subscribe to context changes.
    • consumer: a react component, that allows components to subscribe to context value
    • displayName: can be modified directly, and is showed in DevTools
    • contextType: a property on a class component can be assigned a Context object
    1
    2
    3
    4
    5
    6
    7
    < MyContext.Provider value = {/* some value */ } />

    <MyContext.Consumer>
    {value => /*you can return a component and assign the value to it*/}
    </MyContext.Consumer>

    MyContext.displayName = 'MyDisplayName'
  • useCallback() and useMemo() accept a function and an array of dependencies, the received function will be executed when any of dependencies changed. the former is used to memorize the received function, while the latter is used to memorize the value returned by the received function

    • useCallback() allows you keep same callback after re-render. this method is recommend to use as callback ref to get node after mound
1
2
3
4
 const measuredRef = useCallback(node => {
console.log(node);
}, []);
<h1 ref={measuredRef}>Hello, world</h1>
  • custom hook
    • Custom Hooks let you share stateful logic, not state itself. it aims at to wrap the logic that can be reused.

difference between class and hook

  • class component is hard to reconstruct and decompose
  • compilation of class component will generate a lot of auxiliary functions
  • class component require this when passing a function to a component
1
2
3
4
5
6
7
8
9
10
11
// by a arrow-function. when the parent refresh, a new arrow function will be generated and the offspring will refresh, even the received props haven't change
<button onClick={() => this.handleClick1()}> btn3 </button>

// by bind. the side effect of this is same with the last one
<button onClick={this.handleClick1.bind(this)}> btn2 </button>

// to declare in the constructor, but it cannot pass parameters
constructor(props) { this.handleClick1 = this.handleClick1.bind(this) }

// by the static property of class, same with the last one
handleClick3 = () => { }

redux

concept

1
A(change) --> B(send an `action` to `store`) --> C(`store` dispatch the action to a `reducer`) --> D(the `reducer` return a new state to `store`) --> E(`state` changed)  --> G(execute `listeners`)
  • store a container created by createStore(), where data is changed and saved.

  • state an object, your data

  • action an object, include a type property required and other properties. the kinds of type decide how many actions that a store have.

  • reducer a function, receive an action ,and return a new state instead of change the present state. automatically triggered by store.dispatch()

    • Reducers should be as the parameter pass to the createStore() when initialize the store.

to view when state change

  • changed by props with dispatch, this.props.dispatch({ type: ‘xxx’ })
  • use this.setState() and store.getState() in use store.subscribe(), that used in the component

Redux Methods

  • createStore(), reducers as parameter is required, an initial state if you need, the third argument is enhancer like middleware

  • provider allow the redux hooks and connect to components

  • store.getState() get the present state

  • store.dispatch() sending an action to reducer

  • store.replaceReducer() Replaces the reducer currently used by the store.

  • combineReducers() organize your reducers to manage their own slices of state. accept an object whose values are different reducing functions and turn it into a single reducing function you can pass to createStore.

    1
    combineReducers({ todo: myTodoReducer, counter: myCounterReducer })
  • bindActionCreators is wrap action into dispatch

    1
    2
    3
    type actionCreator = (payLoad: any) => {...{type: string }, ...payload}
    type dispatchAction = (payLoad: any) => dispatch(actionCreator(payLoad))
    (actionCreators: actionCreator | actionCreator[], dispatch: Function) => dispatchAction | dispatchAction[]
  • store.subscribe() receives an listeners function and return a function in which you can disengage the listener.

  • connect return a function which like a HOC accepts a component and wrap it to subscribe store’s updates and able to dispatch actions.

    • how it works? with Provider component provided by redux we can wrap a component and get the component’s context and children, then any nested components can access store with Hooks and connect
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    (mapStateToProps: mapStateToProps, mapDispatchToProps: mapDispatchToProps, mergeProps: mergeProps, options) => ((component) => connectedComponent)

    // combine state and component's props and pass to the component, if this argument is passed to the components, then mapStateToProps will be executed as every time the store and own-props are updated.
    type mapStateToProps = (state: object, ownProps?: object) => stateProps
    // wrap actions as a part of props pass to the component
    type mapDispatchToProps = (dispatch: Function, props?: object) => dispatchProps
    // return an object as a result of mapStateToProps and mapDispatchToProps
    type mergeProps = (stateProps, dispatchProps, ownProps) => mapStateToProps & mapDispatchToProps

    type stateProps = any

    interface dispatchProps {
    dispatchPlainObject: () => dispatch(action)
    }
  • middleware is used to inject a third-party in the redux processing, allow you to do sth (like logging, crash reporting, talking to an asynchronous API, routing, and more) after an action is dispatched and before a reducer update the state.

    1
    (getState: store.getState, action, next: (action) => void) => void
    • action => middleware => reducer => state
    • next is used to pass action to the next middleware. you can pass the current action to continue the middleware chain or pass another action.
    • middleware chin: an action can have an array of middleware that is linked by next.
      • tips: if next is used in a middleware for passing another action, then that action will be directly to the reducer and will not go through its own middleware chain
    • use dispatch inside a middleware will stop current middleware chain and start another middleware chin.
    • it is not different, either use dispatch, or next, or do nothing to stop middleware chain.

lazy loading

  • with React.lazy Suspense import(), we can lazy loading components and can do something in the fallback which will be triggered if the component failed to render
  • with webpack code splitting, each module loaded by import() will be split to separate files.
1
2
3
4
5
const OtherComponent = React.lazy(() => import('./OtherComponent'));

<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>

concepts

  • shouldComponentUpdate VS pureComponent

    • the former is class component’s life cycle, by return a boolean in the function to decide whether the dom should update
    • the later doesn’t implement shouldComponentUpdate, but it has its own way by shallowly compare props and states
    • PureComponent or manually implement shouldComponentUpdate are good methods for avoiding needless re-render of children.
  • virtual DOM

  • fiber

  • uncontrolled and controlled component

    • when dispose Form elements, like input or select, there are two modes uncontrolled and controlled. this is depending on how deep that you want to control the input.
1
2
3
4
5
6
// uncontrolled, get the value with ref
<input type="text" ref={inputRef} />

// controlled, update the input value by update the state, then view update
// data and view always in sync
<input value={state.value} onChange={handleChange} />
  • automatic batching

    • batching update happened when you had multiple state updates, and react will re-render once at the end of a function, not every time the setState is called. however, this is only occurred in a browser event handler. for now in the version 18, updates are batched automatically, regardless of what they’re wrapped by.

    • ReactDOM.flushSync(), this method is used when you don’t want to apply automatic batching. updates in this method will be update immediately, and it’s a sync method, since we know that setState is a async method.

      1
      2
      3
      4
      5
      6
      7
       import { flushSync } from 'react-dom'; // Note: react-dom, not react

      function handleClick() {
      flushSync(() => {
      setCounter(c => c + 1);
      });
      }
  • concurrent mode, found in version 18

    • allow us to bounce back and forth between multiple tasks, but doesn’t mean that those tasks are processing at the same time, rather it’s that one task can be paused while other more urgent task are seen to. once the more urgent one are done, we jump back the less urgent one, bringing with the updated information from the more urgent one.
    • useTransition, this hook is used to wraps a less urgent update.
  • strict modeOfficial Doc, this is used only in the DEV mode. when running in this mode:

    • activates additional checks and warnings for its descendants
    • can be used for any part of your app
    • React intentionally double-invokes effects (mount -> unmount -> mount) for newly mounted components in order to flush out unsafe side effects.

coding tips

  • refresh page by router according to hash value
1
this.props.history.replace({ pathname: this.props.location.pathname, search: `id=${id}&api=${window.location.hash.split('&')[1].split('=')[1]}` })
  • the root element of a component may not need a name
1
2
3
<>
<input ref={inputEl} type="text" />
</>

redux-toolkit

  • core api
    • createAction,createReducer
    • createSlice:including createAction and createReducer
    • PayloadAction:ts 泛型,用以声明 action.payload

createAsyncThunk

accepts a Redux action type string and a callback function that should return a promise. return a standard Redux thunk action creator

web3

window.ethereum (an EIP-1193 compliant provider)
Web3.givenProvider

webpack

module building, browser compatibility, code compressing, code splitting, lazy loading

building process

  1. generate a config from the webpack.config.js and the command line.
  2. use compiler module to create a compilation instance which has access to all modules and their dependencies. execute the compiler.run() to start working. compiler and compilation are the heart of webpack, both of them extend from tapable.
  3. analysis process is started from the entry file. use acron parser to generates AST(Abstract Syntax Tree / 抽象语法树) for the entry file.
  4. traverse through entire AST to create a dependency graph. at this stage, if webpack find any matched rules for loaders, the loaders will convert those codes(e.g. css files) into js, and then Parser parses them into AST.
  5. this process will be repeatedly executed for the each dependency, to recursive traverse.
  6. bundle all the files.
  7. in the above process
    1. webpack compiles the different types of file to js file by loaders
      • loader is responsible for file converting. every file type can have more than one loader, those loaders will be invoked with method chaining in order. so the output of a loader will be the arguments of the next loader.
    2. compiler will throw some hooks when webpack starts/stops, emit assets, watch mode etc. those events can be listened by plugin and allows plugin to intervene the result of output.
      • plugin can extends features. listen events sended by compiler allows a plugin to effect the result.

optimization

  • tree shaking
  • compress code by some plugins, like terser, css minimize
  • code splitting, use import() to split code into multiple chunk and lazy-loading them. import() can cooperate with suspense feature in react.

boost build time

  • webpack cache strategies
  • get precise time by speed-measure-webpack-plugin, like how long the engine spends in each plugin / loader
  • save time from each plugin or loader
    • ts-loader, use happyPackMode or transpileOnly to turn off type checking. the former will implicitly sets transpileOnly: true and will not reports syntactic errors. it is usually used with happypack.
    • fork-ts-checker-webpack-plugin works for ts type checking in a separate process which runs in parallel with webpack

tree shaking

  • after checking import and export, tree shaking will remove the modules which is imported but doesn’t be used. from this point, what method do we use to import file is critical, and we can know tree shaking only supports ES module.

  • to import the specific modules instead of the whole library

    1
    2
    3
    4
    5
    6
    // Import everything (NOT TREE-SHAKABLE)
    import _ from 'lodash';

    // CAN BE TREE SHAKEN
    import { debounce } from 'lodash';
    import debounce from 'lodash/lib/debounce';
  • side effect refer to a function will effect the variables or scope outside the function

  • however, the border between used and not used is not clean, some modules are started to work when it is imported. since object is reference type, which means that if a function’s arguments are object, then any changes on we made on it will be easily effect the data outside the function. so there has a property sideEffects in the package.json to tell webpack whether should be tree shaking.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
      // all the modules have/haven't side effects, and then can't/can be tree shaking
    {
    "sideEffects": true/false
    }
    // give webpack an array with side effects
    {
    "sideEffects": [
    "./src/file1.js",
    "./src/file2.js"
    ]
    }

module federation

to expose some of our components to the outside, and therefor which can be used in other projects.
this feature is considered as an idea of micro-frontend

HTTP

  • http vs https

    • http 请求信息明文传输,https 加密传输
    • 通过SSL证书来验证服务器的身份,并为浏览器和服务器之间的通信进行加密
    • 由于HTTPS需要做服务器、客户端双方加密及解密处理,因此会消耗CPU和内存等硬件资源
  • 三次握手 make sure that the service and the client both can send and receive data

    • 1:客户端发送网络包,服务端收。服务端得出结论:客户端的发送能力、服务端的接收能力正常的。
    • 2:服务端发包,客户端收。客户端得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
    • 3:客户端发包,服务端收。服务端得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
  • URL

    • 保留字符 : : / ; ? #
    • encodeURI 和 decodeURI 函数操作的是完整的 URI,不会编码保留字符。
    • encodeURIComponent 和 decodeURIComponent 函数操作的是组成 URI 的个别组件,会编码任何保留字符

methods

  • post | put | delete contain request body for saving data.

headers

  • content-type

    • application/json:json
    • application/x-www-form-urlencoded:formdata
    • multipart/form-data: 在表单中上传文件时,数据被编码为一条消息,http协议会对参数进行分割
    • text/plain: 数据以纯文本形式(text/json/xml/html)进行编码
  • Content-Disposition: a response header which is indicating if the content is expected to be displayed inline in the browser,or as an attachment to downloaded and saved locally.

    1
    2
    3
    // inline or attachment
    res.set('Content-Disposition', 'attachment; filename=foo.fdf');
    res.send(_res)

    AJAX

  • responseType: XMLHttpRequestResponseType specifying the type of data contained in the response.

    1
    XMLHttpRequestResponseType: "" | "arraybuffer" | "blob" | "document" | "json" | "text";

code

  • 1XX- 信息型,服务器收到请求,需要请求者继续操作。
  • 2XX- 成功型,请求成功收到,理解并处理。
  • 3XX - 重定向,需要进一步的操作以完成请求。
  • 4XX - 客户端错误,请求包含语法错误或无法完成请求。
  • 5XX - 服务器错误,服务器在处理请求的过程中发生了错误。

Restful api(Representation state transfer)

Vscode

vscode setting

markdown lint config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
"security.workspace.trust.untrustedFiles": "open",
"editor.tabCompletion": "on",
"editor.insertSpaces": false,
"editor.tabSize": 4,
"editor.detectIndentation": false,
"files.autoSave": "onFocusChange",
"php.validate.executablePath": "",
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"prettier.jsxSingleQuote": false,
"prettier.semi": false,
"prettier.useTabs": true,
"prettier.tabWidth": 4,
"prettier.jsxBracketSameLine": true,
"prettier.printWidth": 200,
"workbench.colorTheme": "Blackboard",
"javascript.updateImportsOnFileMove.enabled": "always",
"leek-fund.statusBarStock": ["sh000001"],
"settingsSync.ignoredExtensions": [],
"markdown-preview-enhanced.previewTheme": "vue.css",
"[markdown]": {
"editor.defaultFormatter": "yzhang.markdown-all-in-one"
},
"markdownlint.config": {
"MD025": false,
"MD007": false,
"MD010": false
}
}
short key function
Ctrl+Shift+[ 折叠
Ctrl+Shift+] 展开
ctrl+d 选中单词
alt+shift+鼠标点选 多个位置
alt +鼠标点选 选中
alt + z word break
ctrl + shift + L pitch on the same words simultaneously
ctrl + shift + p show command menu
Setting json C:\Users\tong\AppData\Roaming\Code\User
Line break “files.eol”: “\n”
ctrl + g go to a specif line

terms

en ch
closed testing 精密测试

records

2023/7/19

  • CSS filters can form stacking context
  • the property hidden of input does not work in Safari

Time Complexity