模擬面試、簡歷指導、入職指導、計畫指導、答疑解惑 可私信找我~已幫助100+名同學完成改造!
前言
大家好,我是林三心,用最通俗易懂的話講最難的知識點是我的座右銘,基礎是進階的前提是我的初心~
題目
一面
1、['10', '10', '10', '10', '10'].map(parseInt) 的輸出值是什麽?
2、你們現在的技術棧是什麽?為什麽要使用ts?
3、setTimeout的執行過程(事件迴圈,同步、異步)?
4、對Promise的理解,與async、await的區別,async、await是怎麽實作的?
5、解釋 requestAnimationFrame/requestIdleCallback,分別有什麽用?
6、react效能最佳化?
7、說說對flex的理解?
8、回流、重繪是什麽?如何減少回流和重繪?
10、怎麽尋找react頁面卡頓的原因?
11、編程題:實作一個物件的 flatten 方法,如下:
const obj = { a: { b: 1, c: 2, d: { e: 5 } }, b: [1, 3, {a: 2, b: 3}], c: 3 }
flatten(obj){} 結果返回如下:
// { // 'a.b': 1, // 'a.c': 2, // 'a.d.e': 5, // 'b[0]': 1, // 'b[1]': 3, // 'b[2].a': 2, // 'b[2].b': 3 // c: 3 // }
二面
1、說說對web worker的理解
2、service worker和強緩存相比,有哪些優勢?
3、說說對堆疊溢位的理解
4、position中的sticky是什麽,還有哪些其他的?
5、ts中,any和unknown分別是什麽意思?泛型怎麽使用?
6、bind有什麽用?連續多個bind,最後this指向是什麽?
7、webpack的plugin怎麽實作?
8、編程題:現已知一個字串是由正整數和加減乘除四個運算子(+ - * /)組成。例如存在字串 const str = '11+2-3 4+5/2 4+10/5',現在需要將高優先級運算,用小括弧包裹起來,例如結果為 '11+2-(3 4)+(5/2 4)+(10/5)'。註意可能會出現連續的乘除運算,需要包裹到一起。請用 javascript 實作這一過程
三面
1、手寫體:使用TypeScript 實作一個 get 函式來獲取它的內容值
const data = { name: 'tom', age: 18, address: 'xxx' }
2、ts中的 any 、 unknown 的區別
3、有用過ts中的 keyof 嗎?
4、for in/for of的區別?
5、Promise值穿透?
解答
一面
1、['10', '10', '10', '10', '10'].map(parseInt) 的輸出值是什麽?
可轉化為:
['10', '10', '10', '10', '10'].map((num, index) =>parseInt(num, index))
// [10, NaN, 2, 3, 4]
'10'0 -> 10: 進制為0,則預設10進制
'10'1 -> NaN: 1進制不存在
'10'2 -> 2: 2 * 1 + 2 * 0
'10'3 -> 3: 3 * 1 + 3 * 0
'10'4 -> 4: 4 * 1 + 4 * 0
2、你們現在的技術棧是什麽?為什麽要使用ts?
typescript
是
JavaScript
的超集,它本質其實是是在
JavaScript
上添加了
可選靜態型別
和
基於類的物件導向編程
typescript 的特點
可以在編譯期間發現並糾正錯誤
提高可維護性
提高協同開發的效率
支持強型別、介面、泛型、模組
3、setTimeout的執行過程(事件迴圈,同步、異步)?
事件迴圈
1、執行同步程式碼
2、
1
中生成的
微任務
先執行
3、
1
中生產的
宏任務
再執行
同步
簡單來說就是:排隊。程式碼有前後順序,必須按照順序去執行 異步
異步任務可以不阻塞後面的程式碼執行,而是可以同時進行,並且執行完後會有一個異步的回呼。
想起一個故事可以很好的解釋
同步
和
異步
同步:你打電話去書店借書,老板接電話時讓你等著,他去找書,你只能守著電話幹等著
異步:你打電話去書店借書,老板接電話後說等他找到書再打回給你,然後掛電話了,這段找書的時間你可以自由活動
4、對Promise的理解,與async、await的區別,async、await是怎麽實作的?
Promise的理解
顧名思義,
Promise
就是
承諾
的意思,表現在了Promise的狀態一旦改變則不會再變了,如果狀態為
fulfilled
則執行
then
,如果狀態為
rejected
則執行
catch
,Promise 也支持
鏈式呼叫
。我覺得Promise最大的用處就是
解決了回呼地獄,提高了程式碼的可讀性
。常用的方法有
resolve、reject、then、catch、race、all、allSettled、any、finally
async await
async/await
的作用是
用同步的方式執行異步的操作
,它的實作原理,我個人理解就是利用了
Promise
的不斷巢狀,再加上
generator函式
的步驟控制,實作了按順序執行異步操作的效果
補充:async函式返回的是一個Promise
5、解釋 requestAnimationFrame/requestIdleCallback,分別有什麽用?
requestAnimationFrame:
一般間隔是
16ms
,因為大部份電腦都是 每秒60幀 ,所以
1000 / 60 ≈ 16ms
會把每一幀中的所有DOM操作集中起來,在一次重繪或回流中完成,且時間間隔緊緊跟隨瀏覽器的重新整理頻率
如果有隱藏或不可見的元素,將不會進行重繪或回流,減少了cpu、gpu的記憶體使用量
如需取消則使用
cancelAnimationFrame
requestIdleCallback:我的理解就是找瀏覽器空閑時間去執行傳入的回呼,具體也沒在計畫中使用過
6、react效能最佳化?
7、說說對flex的理解?
彈性布局
,設定了
display: flex
的盒子為
彈性盒子
,子元素會自動變成
彈性計畫
,盒子有一根主軸,預設是水平,並且有一個交叉軸(跟主軸垂直)。
彈性盒子的樣式:
flex-direction:定義主軸方向
flex-wrap:是否允許換行
flex-flow:flex-direction 和 flex-wrap的簡寫
justify-content:主軸方向上的對齊方式
align-items:交叉軸方向的對齊方式
align-content:多根軸線的對齊方式
彈性計畫的樣式:
order:定義計畫的排列順序,數值越小排列越靠前,預設0
flex-grow:定義計畫的放大比例,預設為
0
flex-shrink:定義計畫的縮小比例,預設為1
flex-basis:定義了在分配多余空間之前,計畫占據的主軸空間,預設auto
flex:flex-grow、flex-shrink、flex-basis的簡寫
align-self:允許單個計畫設定不同的交叉軸對齊方式
8、回流、重繪是什麽?如何減少回流和重繪?
重繪回流
回流:尺寸、布局改變時,引起頁面重新構建
重繪:元素外觀、風格改變時,不影響布局,則為重繪
區別:回流一定引起重繪,重繪不一定引起回流
瀏覽器幫忙:瀏覽器維護一個佇列,把所有引起回流、重繪的操作放入這個佇列,等佇列到了一定數量或者到了一定的時間間隔,瀏覽器就會清空佇列,進行批次處理。
避免重繪、回流
1、批次修改DOM或者樣式
2、復雜動畫使用絕對定位讓它脫離文件流,不然會影響父元素或後續元素的頻繁回流
3、GPU加速:transform、opacity、filters、will-change等樣式
9、判斷一個物件是陣列的方法?
Object.prototype.toString.call(xxx)
Array.isArray(xxx)
xxx instaceOf Array
10、怎麽尋找react頁面卡頓的原因?
11、編程題:實作一個物件的 flatten 方法,如下:
const obj = { a: { b: 1, c: 2, d: { e: 5 } }, b: [1, 3, {a: 2, b: 3}], c: 3 }
flatten(obj){} 結果返回如下:
// { // 'a.b': 1, // 'a.c': 2, // 'a.d.e': 5, // 'b[0]': 1, // 'b[1]': 3, // 'b[2].a': 2, // 'b[2].b': 3 // c: 3 // }
解題
const isObject = (target) => {
returntypeof target === 'object' && target !== null
}
const flatten = (obj) => {
if (!isObject) return
const res = {}
const dfs = (cur, prefix) => {
if (isObject(cur)) {
if (Array.isArray(cur)) {
cur.forEach((item, index) => dfs(item, `${prefix}[${index}]`))
} else {
for(let key in cur) {
dfs(cur[key], `${prefix}${prefix ? '.' : ''}${key}`)
}
}
} else {
res[prefix] = cur
}
}
dfs(obj, '')
return res
}
二面
1、說說對web worker的理解
1、開啟一個子執行緒,並在此子執行緒進行一些大數據處理或者耗時的操作
2、使用
postMessage
和
onmessage
,實作主執行緒和子執行緒之間的通訊
3、使用
onerror
監聽子執行緒掛了沒
4、
web worker
並沒有改變JavaScript單執行緒的事實
2、service worker和強緩存相比,有哪些優勢?
service緩存沒用過。。
3、說說對堆疊溢位的理解?
常見的情況發生在
大數量遞迴
或
死迴圈
時,就會造成
棧溢位
,因為每次執行程式碼都需要分配一定空間的記憶體,以上兩種情況都會使執行空間超出最大限度,從而報錯
4、position中的sticky是什麽,還有哪些其他的?
static:預設
relative:相對定位,相對於自身定位
absolute:絕對定位,相對於非static的第一個祖宗元素定位
fixed:相對於瀏覽器視窗進行定位
inherit:規定應該從父元素繼承 position 內容的值
sticky:吸頂定位
5、ts中,any和unknown分別是什麽意思?泛型怎麽使用?
any:變量如果是 any 型別,繞過所有型別檢查,直接可使用
unknown:變量如果是 unknow 型別,需要判斷完是什麽型別之後才能使用
6、bind有什麽用?連續多個bind,最後this指向是什麽?
bind
的作用是改變函式執行的指向,且不會立即執行,而是返回一個新的函式,可以自主呼叫這個函式的執行(此函式不可當做建構函式)
連續多個bind之後this指向始終指向第一個
7、webpack的plugin怎麽實作?
一個plugin就是一個類,類裏有一個
apply方法
,每次打包時都會呼叫這個apply,而這個apply方法接受一個參數物件,其中有一個
plugin
方法,此方法中有許多
勾點函式
,且可以決定靜態檔的生成,修改等等
8、編程題:
現已知一個字串是由正整數和加減乘除四個運算子(+ - * /)組成。例如存在字串 const str = '11+2-3 4+5/2 4+10/5',現在需要將高優先級運算,用小括弧包裹起來,例如結果為 '11+2-(3 4)+(5/2 4)+(10/5)'。註意可能會出現連續的乘除運算,需要包裹到一起。請用 javascript 實作這一過程
解答 我比較菜,用的方法也是臨時想出來的,沒有最佳化,大家將就著看吧:
const checkType = (str) => {
if (['*', '/'].includes(str)) return'high'
if (['+', '-'].includes(str)) return'low'
return'number'
}
const addBrackets = (formula) => {
const strs = formula.split('')
let i = 0, j = 1, high = false, res = []
while(j < strs.length) {
const jType = checkType(strs[j])
if (jType === 'low' && !high) {
i = ++j
j++
}elseif (jType === 'low' && high) {
res.push(j++)
i = j++
high = false
}elseif (jType === 'high') {
j++
!high && res.push(i)
high = true
}else {
j++
}
}
if (high) res.push(strs.length)
let add = 0
for(let i = 0; i < res.length; i++) {
const index = res[i]
strs.splice(index + add, 0, add % 2 ? ')' : '(')
add++
}
return strs.join('')
}
三面
1、手寫體:使用TypeScript 實作一個 get 函式來獲取它的內容值
const data = { name: 'tom', age: 18, address: 'xxx' }
解答:
constget = <T extends object, K extends keyof T>(obj: T, key: K): T[K] => {
return obj[key]
}
2、ts中的 any 、 unknown 的區別?
any:變量如果是 any 型別,繞過所有型別檢查,直接可使用
unknown:變量如果是 unknow 型別,需要判斷完是什麽型別之後才能使用
3、有用過ts中的 keyof 嗎?
將一個interface的所有key,匯聚成一個聯合型別,可以用來對傳入key的限制,比如:
interface Target {
name: string,
age: number
}
const fn = (obj: Target, key: keyof Target) => {}
const obj: Target = { name: 'sunshine', age: 18 }
fn(obj, name) // 成功
fn(obj, age) // 成功
fn(obj, height) // 報錯
4、for in/for of的區別?
for in:遍歷物件的key或者陣列的索引
for of:遍歷可叠代物件的值,如陣列、Set
5、Promise值穿透
then或catch沒有傳入函式的話,會發生值穿透,原理是Promise內部檢測如果傳入的是非函式,則會拿上一次的結果包裝成一個返回Promise的函式,達到穿透效果
例如:
Promise.resolve('foo')
.then(Promise.resolve('bar'))
.then(function(result){
console.log(result) // foo
})
但是如果傳入的是函式的話:
Promise.resolve('foo')
.then(() =>Promise.resolve('bar'))
.then(function(result){
console.log(result) // bar
})
結語
我是林三心
一個待過 小型toG型外包公司、大型外包公司、小公司、潛力型創業公司、大公司 的作死型前端選手;
一個偏前端的全幹工程師;
一個不正經的金塊作者;
逗比的B站up主;
不帥的小紅書博主;
喜歡打鐵的籃球菜鳥;
喜歡歷史的乏味少年;
喜歡rap的五音不全弱雞如果你想一起學習前端,一起摸魚,一起研究簡歷最佳化,一起研究面試進步,一起交流歷史音樂籃球rap,可以來俺的摸魚學習群哈哈,點這個,有7000多名前端小夥伴在等著一起學習哦 --> 摸魚沸點
廣州的兄弟可以約飯哦,或者約球~我負責打鐵,你負責進球,謝謝~