1. Array.prototype.sort(cb)
Always pass in comparison callback, as the default of sort()
behavior is:
- first convert to
string
type - then, sort string array
2 examples are given below:
1 | let array1 = [1, 30, 4, 21, 100000]; |
2. NO map
or forEach
on String
String type is array-like
data type, and immutable, no prototype method like map()
, forEach()
, filter()
, reduce()
. BUT, like other array-like
data type, we can use index to access element: str[i]
1 | const str = "abcde"; |
3. oninput
vs onchange
oninput
will trigger every time there is a modification inside<input>
,textarea
, etc.onchange
won’t necessarily trigger for each modification; but will do whenEnter
pressed or focus lost- inside
<input>
,<textarea>
, holding non-whitespace key without release won’t result in letter repeatition, instead, there will be only one letter types in.
4. Don’t use a number
returned comparator directly
Because 0
is falsy
, we should use a boolean
returned comparator instead, as follow:
1 | // BAD |
5. Event
Event delegation
- GOOD:
- Less memory to register event handlers, saving memory
- Dynamically handle element event, eg.: newly added
<li>
can benefit from its parent<ul>
to handle its own event - no memory leak: no need to
removeEventListener()
from a deleted<li>
- BAD:
- Too long time for some event to be handled if the delegation process is too long
- Some event might be stopped by
event.stopPropagation()
- Some event like
onFocus
,onBlur
don’t support event delegation
- NOTE: need to check if
event.target === desiredEle
to respond.
- GOOD:
Default actions
Event handlers are called before the default behavior happens. Eg.
1
2
3
4
5
6
7
8
9
10
11
12
13<!--
link tag <a> won't redirect, because
1. event handler is called
2. event handler prevent the default behavior of <a>
-->
<a href="https://developer.mozilla.org/">MDN</a>
<script>
let link = document.querySelector("a");
link.addEventListener("click", event => {
console.log("Nope.");
event.preventDefault();
});
</script>Key events:
keydown
is enough)cover all keys, while
keyup
only cover part of keys.has default action and is cancelable, by using
preventDefault
; Whilekeyup
has no default action, and is not cancelable.1
2
3
4
5
6
7// 1. e.keyCode
// 2. document.activeElement: the focused Element within the DOM
document.onkeydown = function(e) {
if(e.keyCode === 13) { // The Enter/Return key
document.activeElement.onclick(e);
}
};
compatible for all browser
keep firing when key is held (use
event.repeat
to avoid)1
2
3
4
5
6
7document.addEventListener('keydown', (event) => {
if(event.repeat) {
// key is being held down
} else {
// key is being pressed
}
});
6. How does new
work when instantiate an object?
credit_1: https://segmentfault.com/a/1190000017956545
credit_2: https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
The new
operator is used before a function, like new Foo(…)
. When the code is executed, the following things happen:
An empty object is created:
obj
;Foo
is called onobj
, so nowthis
refer toobj
;obj
inherit fromFoo.prototype
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20function Foo() {
this.name = 'Osama';
this.say = function () {
return "I am " + this.name;
};
}
let obj = new Foo();
// The statement above is equal to [1][2][3] below:
// [1] create a new object using the object literal
// let obj = {};
// [2] add instance properties and methods to `this`
// Foo.call(obj);
// [3] add proto property to `this`
// obj._proto_ = Foo.prototype;
console.log(obj.name); //Osama --- [3]
7. global/window
: default one, if no obj set to this
If there is no calling context, this
will be bound to global
or window
1 | const context = "global"; |
8. Foo.prototype.method=...
vs Foo.prototype={...}
Use Foo.prototype.method=function () {...}
, rather than Foo.prototype={...}
.
- The 1st approach didn’t modify
Foo.prototype.constructor
, so it is stillFoo
; - However, the 2nd one modify it to be
Object
, which is not disired. - Example below can be
1 | // [Credit]: https://stackoverflow.com/questions/8453887/why-is-it-necessary-to-set-the-prototype-constructor |
9. AMD vs. CommonJS vs import/export
CommonJS:
require
&module.exports
(exports
) relavant blogrequire
is a global utility function (obj), with innercache
storing amap <filename, modulePublicAPI>
, by firstly executing module functions, and then exporting module API with the help ofClosure
- get the
code string
of this module; - create empty hooks to link potential public interface
- declare wrapper function
- call wrapper function to execute module, and expose public interface to
module
- store module public interface in require util 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44// https://caomingkai.github.io/2018/10/02/Note-of-Eloquent-JavaScript/
require.cache = Object.create(null);
function require(fileObj) {
if (!require.cache[fileObj.name]) {
let functionStr = fileObj.functionStr; // 1. get the `code string` of this module
let module = {exports: null}; // 2. create empty hooks to link potential public interface
const wrapper = Function('require', 'module', functionStr); // 3. declare wrapper function
wrapper(require, module); // 4. call wrapper function to execute module, and expose public interface to `module`
require.cache[fileObj.name] = module.exports; // 5. store module public interface in require util obj
}
return require.cache[fileObj.name];
}
/* TEST:
`fileObj` simulates a file with name as `a`, and content as `functionStr`
*/
let fileObj = {
name: "a",
functionStr: "let a = 0; function increA() {a += 1;}; function getA(){return a;} module.exports={increA, getA};"
}
function test(){
console.log("require module for 1st time------>");
let module = require(fileObj);
console.log(module.getA()); // 0
module.increA();
console.log(module.getA()); // 1
module.increA();
console.log(module.getA()); // 2
module.increA();
module.increA();
module.increA();
console.log(module.getA()); // 5
console.log("require module for 2nd time------>");
module = require(fileObj);
console.log(module.getA()); // 5
module.increA();
console.log(module.getA()); // 6
}
test();- get the
10. When to use document.write
?
document.write
only works while the page is loading; If you call it after the page is done loading, it will overwrite the whole page.
The following is an legitimate use of document.write
comes from the HTML5 Boilerplate index.html example.
1 | <!-- Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if offline --> |
11. HTML attribute
vs DOM property
Attributes are defined by HTML. Properties are defined by the DOM (Document Object Model).
- A few HTML attributes have 1:1 mapping to properties.
id
is one example. - Some HTML attributes don’t have corresponding properties.
colspan
is one example. - Some DOM properties don’t have corresponding attributes.
textContent
is one example. - Many HTML attributes appear to map to properties … but not in the way you might think!
Attributes initialize DOM properties and then they are done. Property values can change; attribute values can’t.
For example, when the browser renders <input type="text" value="Bob">
, it creates a corresponding DOM node with a value
property initialized to “Bob”.
When the user enters “Sally” into the input box, the DOM element value
property becomes “Sally”. But the HTML value
attribute remains unchanged as you discover if you ask the input element about that attribute: input.getAttribute('value')
returns “Bob”.
The HTML attribute value
specifies the initial value; the DOM value
property is the current value.
12. document.load()
vs document DOMContentLoaded()
DomContentLoaded
fires afterdomcument
is created; But css files,images and frame are not yet loadedload
fires after all resources are loaded.
13. When to usePromise.resolve()
?
Promise.resolve()
will immediately change the status and broadcast the value, skipping the execution of executor. The consumers registered in then()
will be invoked immediately.
So, we can use promise.resolve()
, if we wanted to invoke consumers registered in then()
, and don’t care the executor.
14. CSS preprocessor
Why use it?
variables:
font-size: $fontSize;
nested selector: clear structure and less redundant selectors
1
2
3
4
5
6
7
8
9nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
}will be converted to CSS as follows:
1
2
3
4
5
6
7
8nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav li {
display: inline-block;
}@mixin
and@include
: make groups of CSS declarations that you want to reuse throughout your site[Best Practice:] use a mixin to inject dynamic values into repeated constructs
1
2
3
4
5
6@mixin transform($property) {
-webkit-transform: $property;
-ms-transform: $property;
transform: $property;
}
.box { @include transform(rotate(30deg)); }will be converted to CSS as follows:
1
2
3
4
5.box {
-webkit-transform: rotate(30deg);
-ms-transform: rotate(30deg);
transform: rotate(30deg);
}inheritance selector:
%name
and@extend
: share a set of CSS properties from one selector to another;[Best Practice:] Only use
@extend
when the rulesets that you are trying to DRY out are inherently and thematically related
15. HTML Accessibility
[Why need it]:
1 | 1. not only for <u>people with disability</u> (better experience), |
- semantic HTML. Validating it is a good start, as is using an Auditing tool.
- Check that your content makes sense when the CSS is turned off.
- keyboard accessible. Test using Tab, Return/Enter, etc.
- text alternatives.
<img alt="Mingkai's Photo />"
- element relationships.
<label for="name">Fill in your name:</label> <input type="text" name="name />"
- color contrast
- hidden content is visible by screenreaders: Use
z-index
, instead ofvisibility: hiden;
anddisplay: none
. - client-side form validation: Make sure that functionality is usable without JavaScript wherever possible.
- ARIA: Accessible Rich Internet Applications
16. data-*
: HTML syntax vs. JS access vs. CSS access
credit: MDN: Using data attributes
data-*
allow us to store extra information on standard, semantic HTML elements.
HTML syntax:
data-columns
1
2
3
4
5
6
7<article
id="electric-cars"
data-columns="3"
data-index-number="12314"
data-parent="cars">
...
</article>JS access:
dataset
(NOTE: dashes are converted to camelCase)[Read & Write:] each property is a string and can be read and written. In the above case setting
article.dataset.columns = 5
would change that attribute to"5"
.1
2
3
4
5
6
7
8
9
10// 1st approach: standard (Read & Written)
const article = document.querySelector('#electric-cars');
article.dataset.columns // "3"
article.dataset.indexNumber // "12314"
article.dataset.parent // "cars"
// 2nd approach: getAttribute() (ONLY Read)
article.getAttribute('data-columns') // "3"
article.getAttribute('data-index-number') // "12314"
article.getAttribute('data-parent') // "cars"
CSS access:
attr(name)
to get attribute value forname
1
2
3
4
5
6
7
8
9
10
11
12// use case 1:
article::before {
content: attr(data-parent);
}
// use case 2:
article[data-columns='3'] {
width: 400px;
}
article[data-columns='4'] {
width: 600px;
}
17. How does browser render a webpage?
- Critical Rendering Path: (DON’T put any other task like
img
download in CRP)- 1.1
HTML
=>DOM tree
- 1.2
CSS
=>CSSOM tree
- 1.3
JS
download & execute - 2.0
DOM Tree
+CSSOM Tree
+JS
=>Render Tree
- 3.0
Layout
(ReFlow
: related toposition
,layout
,height
,width
) - 4.0
Paint
(RePain
: related tocolor
, etc not related to layout)
- 1.1
CSS
is render-blocking source, as it is cascading, has to parse to the end to form a determinated rendering rule; It can also block JS, as JS has to wait complete CSSOM tree to finish, to modify the CSSJS
is HTML parse-blocking source, as it don’t need to wait DOM to finish, rather, it can change the DOM in the fly.- regular script: download & execution will block HTML parsing
- script async: download won’t block (async download), execution will block HTML parsing
- script defer: download won’t block (async download),, execution won’t block HTML parsing
18. CSS: float
set & clear
float
will put element on its left/right side of its container(box model)floated element is removed from normal flow, but still remaining a part of flow
float
will force some value ofdisplay
to beblock
, like:display: inline
,inline-block
,table-cell
clear
will specify an element must be moved below a floating element.If an element contains only floated elements, its height collapses to nothing. Solution clearfix as following:
1
2
3
4
5#container::after {
content: "";
display: block;
clear: both;
}
19. CSS: positioning
20. HTML: People you may know
1 |
|
21. UI: create a tooltip
写一个类似tooltip的widget,当用户把鼠标放在LinkedIn页面上某个联系人的名字上时,会出现一个类似tooltip的预览框,里面有该用户的头像,姓名,degree以及title。要求先用HTML以及CSS mock up下大致的layout,然后用AJAX得到所需要显示的用户信息。?
1 |
|
22. JS: memorize function
Create a memo function take a function and returns a new one. The returned function can cache the result for corresponding parameters.
1 | // Approach 1: store result onto returned function (self-contained) |
23. UI: Inifinite scroll
24. JS: lazy load
[Credit] web browser renders a webpage by reading it’s markup (HTML). If the markup contains an external JavaScript file, the browser stops loading the markup and starts downloading that external JavaScript – this causes a block in webpage rendering (known as render blocking or parser blocking).
1 | window.onload = function() { |
26. UI: autocomplete
1 |
|
27. UI: widget
build a widget with 4 lists and 3 nested list, nested can be span/collapse when clicking on parents, highlight txt when hover大概是
1 |
|
28: Browser: GET v.s. POST
29. UI: thumb up
写一个类似于点赞功能的ui,点赞之后旁边的数字+1,取消之后-1写html的时候问了怎么改进accessiblity和symentic?用了一些
30. JS:
- 几座小岛那题
- Lowest Common Ancestor of a Binary Search Tree 还没不及写完 只是讲一下做法而已
- 衣而期
- 衣而溜
Debounce & Throttle
1 | function debounce_leading(fn, period) { |
Autocomplete
1 | function ele(id) { |
II.On-site
Web & Browser
Progressive web app
Security: XSS,
Http1.0 vs http1.1 vs http2
- keep alive: long polling
- header compressed
- binary stream transmission
web socket vs. server side event(not supported by all) vs. long polling
Service worker vs. Web worker vs. Web socket
PWA:link
- Service Worker
- Client side storage => Indexed DB
- Web push/notification API (service worker)
- App shell
short connection & persistent connect vs. long polling & polling reference
HTTP与浏览器缓存
- 两方的流程
- 图1:server 根据需求决定 cache 的config
- 图2:browser根据 server 发来的 cache config,决定是否应用cache,or直接请求
- 顺序
- Cache-Control —— 请求服务器之前
- Expires —— 请求服务器之前
- If-None-Match (Etag) —— 请求服务器
- If-Modified-Since (Last-Modified) —— 请求服务器
- Expires + Cache-Control: (强缓存)
- Cache-Control 优先级高于 Expires
- 强缓存 优先判断;然后判断弱缓存
- Last-Modified + If-Modified-Since (弱缓存)
- server response 中带有
Last-Modified: time_k
, 让browser将资源缓存起来(attaching Last-Modified) - browser request 中带有
If-Modified-Since:time_k
(attached Last-Modified),发给server,让其决定是否新鲜
- server response 中带有
- ETag + If-None-Match: (弱缓存)ETag is unique MD5 digest of resource
- server response 中带有
ETag: val
, 让browser将资源缓存起来(attaching ETag) - browser request 中带有
If-None-Match: val
(attached Last-Modified),发给server,让其决定是否新鲜
- server response 中带有
ETag
的优先级比Last-Modified
更高- cache control: no cache vs no store
- no cache: 告诉browser:不能直接用cache,browser必须发请求,server不反悔 content,而是告诉browser: 可以使用cache(304并且会显示一个Not Modified)
- no store:告诉browser:请求得到的内容,你不可以缓存起来,每次都必须从server拿资源
- 两方的流程
Storage
local storage(5M): 永远存在(网页关闭也存在),limited to 域名
storage event:
1
2
3
4
5window.addEventListener('storage',function(e){
console.log('key=' + e.key);
console.log('oldValue=' + e.oldValue);
console.log('newValue=' + e.newValue);
})
2. sessin storage(5M):临时存在(网页关闭就消失),limited to 本域名、本网页存在期间
3. cookie(4k): cookie可以设置路径path,所有他要比上面两个多了一层访问限制domain => path
4. session:
JSONP: https://www.w3schools.com/js/js_json_jsonp.asp
- vs. CORS
Optimistic UI update: like button
encodeURIComponent
vsdecodeURIComponent
1
CSS + HTML
Accessibility: ARIA
checklist:
- Check ARIA roles here
<img alt="" >
<div tabindex='0' >
keyboard nav using tab<p tabindex='-1'>
keyboard focus using arrow (since children will also be tabable if parent istabindex='0'
)<label for='name input'>
<div aria-labelledby='title'>
<div role='menu'>
<div aria-valuemax='100'>
<div aria-valuenow='78'>
<span aria-checked='false'>
<input aria-required='true'>
<span role='alert'>
In HTML5, all ARIA attributes validate. The new landmark elements (
<main>
,<header>
,<nav>
etc) have built-in ARIA roles, so there is no need to duplicate them.温度计
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<div id="percent-loaded"
role="progressbar"
aria-valuenow="75"
aria-valuemin="0"
aria-valuemax="100"
/>
// OR JS
<script>
// Find the progress bar <div> in the DOM.
var progressBar = document.getElementById("percent-loaded");
// Set its ARIA roles and states,
// so that assistive technologies know what kind of widget it is.
progressBar.setAttribute("role", "progressbar");
progressBar.setAttribute("aria-valuemin", 0);
progressBar.setAttribute("aria-valuemax", 100);
// Create a function that can be called at any time to update
// the value of the progress bar.
function updateProgress(percentComplete) {
progressBar.setAttribute("aria-valuenow", percentComplete);
}
</script>
innerText vs innerHtml vS textContent
- innerText is aware of CSS styling, it will trigger a reflow, whereas textContent will not.
- innerText will not include text that is hidden by CSS
- textContent include text no matter the style is hidden or not! GOOD! NO Reflow!
display vs. float vs. position
BFC(Box Formatting Context)
BFC(Block formatting context)直译为”块级格式上下文”。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干
BFC布局规则:
- 内部的Box会在垂直方向,一个接一个地放置。
- Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
- 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
- BFC的区域不会与float box重叠。
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
- 计算BFC的高度时,浮动元素也参与计算
BFC 形成条件:
- 根元素
- float属性不为none
- position为absolute或fixed
- display为inline-block, table-cell, table-caption
- overflow不为visible
<form>
:<fieldset> + <legent> + <input> + <label>
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
31
32
33
34
35
36<form>
<fieldset>
<legend>Your income is:</legend>
<p>
<input type="radio" name="inc" value="0-50K" id="0-50K" />
<label for="0-50K">$0-50,000 USD</label>
</p>
<p>
<input type="radio" name="inc" value="50-100K" id="50-100K" />
<label for="50-100K">$50,000-100,000 USD</label>
</p>
<p>
<input type="radio" name="inc" value="100K+" id="100K+" />
<label for="100K+">$100,000+ USD</label>
</p>
</fieldset>
<fieldset>
<legend>Your status is:</legend>
<p>
<input type="radio" name="status" value="single" id="single" />
<label for="single">single</label>
</p>
<p>
<input type="radio" name="status" value="married" id="married" />
<label for="married">married</label>
</p>
<p>
<input type="radio" name="status" value="partner" id="partner" />
<label for="partner">domestic partner</label>
</p>
</fieldset>
<p>This form goes on with another 97 questions....</p>
<input type="submit" value="Submit" />
</form>How to know which
<input type='radio' />
is selected?1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<form action="#n" name="theForm">
<label for="gender">Gender: </label>
<input type="radio" name="genderS" value="1" checked> Male
<input type="radio" name="genderS" value="0" > Female<br><br>
<a href="javascript: submitForm()">Search</A>
</form>
<script>
var radios = document.getElementsByName('genderS');
for (var i = 0, length = radios.length; i < length; i++)
{
if (radios[i].checked)
{
// do whatever you want with the checked radio
alert(radios[i].value);
// only one radio can be logically checked, don't check the rest
break;
}
}
</script>
<button type='button'>
??1
2
3
4
5
6
7
8
9
10
11If you include a button in a form element without specifying it's just a regular button, it defaults to a submit button.
<form>
<button>I will submit the form when clicked!</button>
</form>
vs
<form>
<button type='button'>I won't!</button>
</form><input type="button" > vs <button type='button'>
Unlike
<input>
tags,<button>
‘s can contain other html elements as their labels.<input type="button">
can only accept a string as its label text (css styles not withstanding).Additionally, the
<button>
element accepts a wide range of uncommon but useful attributes regarding multiple forms and click actions. See the MDN page for more details.HTML5
New elements: all new elements are block-level elements
semantics
- article
- aside
- details
- figcaption
- figure
- footer
- header
- main
- mark
- nav
- section
- summary
- time
HTML migration
1
2
3
4
5<div id="header"> <header>
<div id="menu"> <nav>
<div id="content"> <section>
<div class="article"> <article>
<div id="footer"> <footer>
4. style guid
1. `<!doctype html>`
2. `<html lang="en-US">`
3. `<head> <meta charset="UTF-8"> </head>`
4. `<meta name="viewport" content="width=device-width, initial-scale=1.0">`
5. all lower case
6. `<img alt="" />`
AJAX
1
2
3
4
5
6
7
8
9
10
11
12let xhr = new XMLHttpRequest();
xhr.onload = function() {
if (xhr.readyState = 4 && xhr.status == 200) {
// manipulate DOM
console.log(xhr.responseText);
} else {
console.log(xhr.status);
}
};
xhr.open("GET", url, true);
xhr.send();How to lazy load
<img>
& how to avoid unnecessary traffic?Browser first download, and then use image in document
new Image()
: The Image() constructor creates a newHTMLImageElement
instance. It is functionally equivalent todocument.createElement('img')
.img.onload
data-imgSrc
<=>e.dataset.imgSrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16(() => {
// Page is loaded
const objects = document.getElementsByClassName('asyncImage');
Array.from(objects).map((item) => {
// Start loading image
const img = new Image();
img.src = item.dataset.src;
// Once image is loaded replace the src of the HTML element
img.onload = () => {
item.classList.remove('asyncImage');
return item.nodeName === 'IMG' ?
item.src = item.dataset.src :
item.style.backgroundImage = `url(${item.dataset.src})`;
};
});
})();
5. `onscroll` lazy load
1
2
3
4
5
6
7
8
9
10
11
12
13
14
let lazyImages= [...document.querySelectorAll('.lazy-image')];
let inAdvance = 300;
function lazyLoad() {
lazyImages.forEach(image => {
if (image.offsetTop < window.innerHeight + window.scrollY + inAdvance) {
image.src = image.dataset.src;
}
})
}
lazyLoad();
window.addEventListener('scroll', _.throttel(lazyLoad, 50));
window.addEventListener('resize', _.throttel(lazyLoad, 50));
6. NEVER set `<img src="">`: will load this page 2nd time
7.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<img src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="https://images.unsplash.com/photo-1524654458049-e36be0721fa2?ixlib=rb-0.3.5&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ&s=1a6782be5cdb94b780ed9d4a79de7041" alt="">
<style>
// These styles keep the aspect ratio of img.
img {
max-width: 100%;
height: auto;
margin: 0 0 1rem;
border: 4px solid orange;
box-sizing: border-box;
}
</style>
<script>
[...document.querySelectorAll('[data-src]')]
.map(img => {
img.addEventListener('click', e => {
img.src = img.dataset.src)
}
})
</script>
JS Lib: (scroll + API)
Write a Promise (then, catch, finally)
Debounce & Throttle & QueuedCall:
⚠️: this 的处理,传入的fn 有可能内部带有this,那么debounced_fun有可能这样被调用:
this.debounced_fn(args)
throttle其实就是 debounce 的“覆盖式”调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19throttle_with_last_call: (func, limit, context) => {
let lastFunc
let lastRan
return function() {
const args = arguments
if (!lastRan) {
func.apply(context, args)
lastRan = Date.now()
} else {
clearTimeout(lastFunc)
lastFunc = setTimeout(function() {
// if ((Date.now() - lastRan) >= limit) {
func.apply(context, args)
lastRan = Date.now()
// }
}, limit - (Date.now() - lastRan))
}
}
}QueuedCall: 对每次fn 调用都会执行,不会丢掉;但是是以固定频率执行的
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
31
32
33
34
35
36
37
38
39
40
41
42
43function queue(fn, wait) {
let params = [];
let context = null;
let isActive = false;
function executePeriodically() {
isActive = true;
if (params.length > 0) {
setTimeout(() => {
fn.apply(context, params.shift());
executePeriodically();
}, wait);
} else {
isActive = false;
}
}
let queuedFun = function(...args) {
context = this;
params.push(args);
if (!isActive) {
executePeriodically();
}
};
return queuedFun;
}
// Testing
function loggingIncre(i) {
console.log(i);
}
let queuedFun = queue(loggingIncre, 1000);
for (let i = 0; i < 2; i++) {
queuedFun(i);
}
setTimeout(() => {
queuedFun(1111);
setTimeout(() => {
queuedFun(2222);
}, 3000);
}, 3000);
Memoize: weakMap的使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22function memoize(func, resolver) {
if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
throw new TypeError('Expected a function')
}
const memoized = function(...args) {
const key = resolver ? resolver.apply(this, args) : args[0]
const cache = memoized.cache
if (cache.has(key)) {
return cache.get(key)
}
const result = func.apply(this, args)
memoized.cache = cache.set(key, result) || cache
return result
}
memoized.cache = new (memoize.Cache || Map)
return memoized
}
memoize.Cache = Map
export default memoizeInfinite scroll
Window.scrollY
vs.element.scrollTop
: 都表示上侧滑出去多少Window.scrollX
vs.element.scrollLeft
都表示左侧滑出去多少onscroll
要绑定在 镶有滚动条的 div/window 上,而不是内容div上window上的距离判断: div mustn’t have gap from window
1
2
3
4
5
6
7
8
9
10
11
12<body >
<div id="scrollContainer">
<br/><br/><br/><br/><br/><br/><br/><br/><br/> ... <br />
</div>
</body>
<script>
const scrollContainer = document.getElementById("scrollContainer");
const rect = scrollContainer.getBoundingClientRect();
const deltaBottom = rect.bottom - window.innerHeight;
</script>
2. div上的距离判断:
1
2
3
4
5
6
7
8
9
10
<div id="scrollContainer">
<br/><br/><br/><br/><br/><br/><br/><br/><br/> ... <br />
</div>
<script>
const scrollContainer = document.getElementById("scrollContainer");
const rect = scrollContainer.getBoundingClientRect();
const deltaBottom = scrollContainer.scrollHeight - scrollContainer.clientHeight - scrollContainer.scrollTop;
</script>
- LeetCode:
- K Closest Points to Origin
- quick select
- heap
- Maximum Subarray
- DP 2-d => DP 1-d
- accum array
- Integer => String
- details: ‘’
- K Closest Points to Origin
Product Taste
问最喜欢的app,linkedin有什么要改进的地方,平时上那些技术网站论坛
- LinkedIn:
- like concise and clean UI, without distraction (compared to FB)
- like positive and supportive environment
- like the new action button group, give more accurate react (Thoughts on new buttons)
- Improvement:
- Click on link: pop out detail page, have to click close. Can we use touch?
- Can we share file on home screen?
Stripe
- harmonious color skeme / animation
- deliver more info with limited view port
- debate on this: focus with margin or info with less margin
- depends on business mode
- LinkedIn:
比如谈一次失败的经历;如果你和其他人意见不一致时怎么处理等。
- That not uncommon at work
- Something didn’t handle well, exist ambiguity. Opportunity for improvement.
- Talk directly, try to understand other’s point of view. If still cannot come to an agreement. No need to be hostile, as both parties’ goal is to improve sth
- time to bring more ideas in, from different perspectives: PM, designer, backend, frontend, CS, even customers
- eg: whether we should use PureComponent in Redux project
谈谈你喜欢和不喜欢的App,以及LinkedIn App。我说我不怎么用LinkedIn App,谈谈网页版的行不行,他说没问题。
设计一个dashboard,dashboard是一个地图,当有新用户注册账号时,需要实时在dashboard上显示用户位置?
follow up:前端用什么library?(d3.js),需要向前端发送哪些数据?(经纬度或者geohash),push vs pull?怎么实现push service?(消息队列)?怎么测试?用网页写一个带简单 UI 的计算器。有点 Leetcode 224 的意思,但是 UI 的行为要符合简单的计算器,比如屏幕上显示 1 的时候,输入 2,要变成12,但是显示 0 的时候,输入 1,就要变成 1。Edge case 比较多,要好好跟考官交流。一开始只让写有 + 跟 = 就行了。写的不太好,这里又我面试完写的完全版: https://gist.github.com/d6u/2e982bdc965e14ce12a545e6996f0af4 大家可以一起交流。带 +、-、*、/。面试的时候提了 reverse polish notation 但是没用。-baidu 1point3acres
11:00-12:00,一位面试官。题目是给了个地图,上面有很多点, 每个点是个object, x, y 坐标都给了, 比如{x: 5, y: 5}已知 包含所有点的 array, 某一个点,和半径d, 写一个function 返回到这个点的距离小于或等于d 的所有点。怎么优化。我当时答得是把整个地图分成小的区域,每一小块2d的正方形。然后找这个点所在的方块和周围的几个方块。这样就不用遍历地图里所有的点了。
这一轮和manager聊,学习经历和工作经历,全程聊天穿插一些behavior question。你想给LinkedIn增加哪些新功能。
product and cultule fit。 说一个你最喜欢的应用, 为什么喜欢,还有哪些需要改进的地方。你想给LinkedIn增加哪些新功能(这一轮又问到了)。
1:00-2:00。还是两位面试官。 系统设计。linkedin新加的功能, 页面的右下角可以发messenger. 对于messenger这个feature, 先列一下有哪些功能要实现。然后对每个功能讲讲怎么实现。
题目是写一个function实现计算器里的undo以及redo功能。其实就是考数据结构里的stack。最后的拓展题感觉在问system design,问我如果这种undo以及redo操作是用在占据很大存储空间以及用户量很大的data上该怎么办,我说那就给每个数据加上index,undo以及redo只用在index上,最后再用index去取数据。。。
13:30-14:15,product and cultule fit。这轮主要就是扯淡。。。问到好多UI以及设计方面的问题,比如谈谈你对client side rendering以及server side rendering的理解,说一个你最喜欢的应用并列举下优缺点,LinkedIn还有哪些需要改进的地方等等等等。。。
主要根据简历的情况,很随机地问了很多behaviour的问题,所以简历里写的东西自己一定要熟悉,manager人好好呀,感觉特别亲和,有活力。
设计一个系统或者service,包括分析QPS, concurrent user那些,到后台用哪种database存,push or pull,这些,结果完全又不按套路出牌,让设计一个日历,要写detail的HTML和js代码,这一轮的面试小哥非常严肃,提示也比较confusing….楼主表示全程很懵逼,他问的问题也比较随机,看到你写到某个地方的时候,会突然根据你写的提出一个问题,感觉他有点想到什么问什么。
高频题:地图上显示新注册用户的位置。 很多很多follow up, 比如:更新频率如何设定,短时间大量用户注册怎么处理,后端api返回的数据结构,polling vs socket,是否需要实时更新等等。
这个是一个小时。主要考验你的是宏观的设计。例如后端该有什么 endpoint,前端什么时候要用这些 endpoint。前端每个 page 该怎么和对方交流。一般会叫你设计一个 App。面试我的时候是给设计 linkedin 的 search。这轮之需要画一些 diagram 和 flowchart 就好,不需要写 code。
这一轮比较奇葩。要求你找一个你最喜欢的网站,然后讲你为什么喜欢。然后如果你是PM,你会怎么改进那个网站。考的更多的是你对 human computer interaction 的理解。大多数是学校里学 UI 时候学的东西。
Word ladder 1 / 2
简历
1.