你盼世界,我盼望你無bug
。Hello 你們好!我是霖呆呆!javascript
哈哈😄,這是一篇面試總結文章,抱歉,webpack
和HTTP
系列的先暫緩一下更新哈,Sorry~css
這篇文章是呆呆本身近期的一些面試彙總,經驗是2年,算了一下有128道,基本都寫了比較完善的答案,就算沒有寫也有推薦一些好的文章連接,文章篇幅較大,整理總結也花費了不少的時間和心血,題目也是根據公司規模的大小從易到難,算是見證了呆呆面試過程當中的不足與成長吧 😅。還但願能幫助到正在一塊兒努力求生存的小夥伴們。html
另外,看到標題了嗎?"掘金技術徵文"
,嘻嘻,要不要考慮幫這麼"用心"
的呆呆拿拿大獎呢?放心放心,要真成了好處少不了大家😋。前端
全部文章內容都已整理至 github.com/LinDaiDai/n… 快來給我Star呀😊~vue
(由於近期面的主要都是一些深圳的中小公司,他們也還在招聘中,因此不便透露公司名稱,還請你們理解...)java
4月22日上午node
缺點: 不一樣瀏覽器對web標準默認值不一樣,因此更容易出現對瀏覽器的兼容性問題。react
改變a標籤css屬性的排列順序webpack
只須要記住LoVe HAte
原則就能夠了:ios
link→visited→hover→active
複製代碼
好比下面錯誤的代碼順序:
a:hover{
color: green;
text-decoration: none;
}
a:visited{ /* visited在hover後面,這樣的話hover事件就失效了 */
color: red;
text-decoration: none;
}
複製代碼
正確的作法是將兩個事件的位置調整一下。
注意⚠️各個階段的含義:
a:link
:未訪問時的樣式,通常省略成a a:visited
:已經訪問後的樣式 a:hover
:鼠標移上去時的樣式 a:active
:鼠標按下時的樣式
const text = document.getElementById('text');
text.onclick = function (e) {
console.log('onclick')
}
text.onfocus = function (e) {
console.log('onfocus')
}
text.onmousedown = function (e) {
console.log('onmousedown')
}
text.onmouseenter = function (e) {
console.log('onmouseenter')
}
複製代碼
答案:
'onmouseenter'
'onmousedown'
'onfocus'
'onclick'
複製代碼
對某些數據的修改就能自動更新視圖,讓開發者不用再去操做DOM,有更多的時間去思考業務邏輯。
首先Vue最核心的兩個特色,響應式和組件化。
響應式:這也就是vue.js最大的優勢,經過MVVM思想實現數據的雙向綁定,經過虛擬DOM讓咱們能夠用數據來操做DOM,而沒必要去操做真實的DOM,提高了性能。且讓開發者有更多的時間去思考業務邏輯。
組件化:把一個單頁應用中的各個模塊拆分到一個個組件當中,或者把一些公共的部分抽離出來作成一個可複用的組件。因此組件化帶來的好處就是,提升了開發效率,方便重複使用,使項目的可維護性更強。
虛擬DOM,固然,這個不是vue中獨有的。
缺點:基於對象配置文件的寫法,也就是options寫法,開發時不利於對一個屬性的查找。另一些缺點,在小項目中感受不太出什麼,vuex的魔法字符串,對ts的支持。兼容性上存在一些問題。
hash
模式的URL
中會夾雜着#
號,而history
沒有。Vue
底層對它們的實現方式不一樣。hash
模式是依靠onhashchange
事件(監聽location.hash
的改變),而history
模式是主要是依靠的HTML5 history
中新增的兩個方法,pushState()
能夠改變url
地址且不會發送請求,replaceState()
能夠讀取歷史記錄棧,還能夠對瀏覽器記錄進行修改。URL
向後端發送HTTP
請求的時候,好比常見的用戶手動輸入URL
後回車,或者是刷新(重啓)瀏覽器,這時候history
模式須要後端的支持。由於history
模式下,前端的URL
必須和實際向後端發送請求的URL
一致,例若有一個URL
是帶有路徑path
的(例如www.lindaidai.wang/blogs/id
),若是後端沒有對這個路徑作處理的話,就會返回404
錯誤。因此須要後端增長一個覆蓋全部狀況的候選資源,通常會配合前端給出的一個404
頁面。hash:
window.onhashchange = function(event){
// location.hash獲取到的是包括#號的,如"#heading-3"
// 因此能夠截取一下
let hash = location.hash.slice(1);
}
複製代碼
(技術棧是Vue
,沒用過react
)
同上
4月22日下午
null
表示一個"無"
的對象,也就是該處不該該有值;而undefined
表示未定義。Number(null)
爲0
,而undefined
爲NaN
。使用場景上:
null
:
undefined
:
冒泡排序:
function bubbleSort (arr) {
for (let i = 0; i < arr.length; i++) {
let flag = true;
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
flag = false;
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
if (flag) break;
}
}
複製代碼
這個是優化事後的冒泡排序。用了一個flag
來優化,它的意思是:若是某一次循環中沒有交換過元素,那麼意味着排序已經完成了。
冒泡排序總會執行(N-1)+(N-2)+(N-3)+..+2+1趟,但若是運行到當中某一趟時排序已經完成,或者輸入的是一個有序數組,那麼後邊的比較就都是多餘的,爲了不這種狀況,咱們增長一個flag,判斷排序是否在中途就已經完成(也就是判斷有無發生元素交換)
數組去重:
Array.form(new Set(arr))
[...new Set(arr)]
for
循環嵌套,利用splice
去重indexOf
或者includes
去重sort
排序,而後用一個指針從第0
位開始,配合while
循環去重固然還有不少,例如用filter、reduce、Map、Object
等,具體能夠看:
Array.form(new Set(arr))
或[...new Set(arr)]
var arr = [1,1,2,5,6,3,5,5,6,8,9,8];
console.log(Array.from(new Set(arr)))
// console.log([...new Set(arr)])
複製代碼
for
循環嵌套,利用splice
去重:
function unique (origin) {
let arr = [].concat(origin);
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] == arr[j]) {
arr.splice(j, 1);
j--;
}
}
}
return arr;
}
var arr = [1,1,2,5,6,3,5,5,6,8,9,8];
console.log(unique(arr))
複製代碼
新建數組,利用indexOf
去重:
function unique (arr) {
let res = []
for (let i = 0; i < arr.length; i++) {
if (!res.includes(arr[i])) {
res.push(arr[i])
}
}
return res;
}
var arr = [1,1,2,5,6,3,5,5,6,8,9,8];
console.log(unique(arr))
複製代碼
先用sort
排序,而後用一個指針從第0
位開始,配合while
循環去重:
function unique (arr) {
arr = arr.sort(); // 排序以後的數組
let pointer = 0;
while (arr[pointer]) {
if (arr[pointer] != arr[pointer + 1]) { // 若這一項和下一項不相等則指針往下移
pointer++;
} else { // 不然刪除下一項
arr.splice(pointer + 1, 1);
}
}
return arr;
}
var arr = [1,1,2,5,6,3,5,5,6,8,9,8];
console.log(unique(arr))
複製代碼
4月23日上午
(從這家公司開始面試稍微有些難度了,面試官小哥哥人也很好,剛開始是一個高冷男神,可是在呆呆的猛烈回答下也終於仍是對我露出了微笑😄,還說他也是掘友,有看過個人文章...掘友真是無處不在啊,感動😹)
這道題我會先大概介紹一下Promise
:
Promise
是一個對象,它表明了一個異步操做的最終完成或者失敗。因爲它的then
方法和catch、finally
方法會返回一個新的Promise
因此能夠容許咱們鏈式調用,解決了傳統的回調地獄問題。
再說一下then
以及catch
方法:
(此處我是直接拿我以前的一篇文章《45道Promise題》那裏的總結)
Promise
的狀態一經改變就不能再改變。(見3.1).then
和.catch
都會返回一個新的Promise
。(上面的👆1.4證實了)catch
無論被鏈接到哪裏,都能捕獲上層未捕捉過的錯誤。(見3.2)Promise
中,返回任意一個非 promise
的值都會被包裹成 promise
對象,例如return 2
會被包裝爲return Promise.resolve(2)
。Promise
的 .then
或者 .catch
能夠被調用屢次, 但若是Promise
內部的狀態一經改變,而且有了一個值,那麼後續每次調用.then
或者.catch
的時候都會直接拿到該值。(見3.5).then
或者 .catch
中 return
一個 error
對象並不會拋出錯誤,因此不會被後續的 .catch
捕獲。(見3.6).then
或 .catch
返回的值不能是 promise 自己,不然會形成死循環。(見3.7).then
或者 .catch
的參數指望是函數,傳入非函數則會發生值透傳。(見3.8).then
方法是能接收兩個參數的,第一個是處理成功的函數,第二個是處理失敗的函數,再某些時候你能夠認爲catch
是.then
第二個參數的簡便寫法。(見3.9).finally
方法也是返回一個Promise
,他在Promise
結束的時候,不管結果爲resolved
仍是rejected
,都會執行裏面的回調函數。另外也能夠說一下finally
方法:
.finally()
方法無論Promise
對象最後的狀態如何都會執行
.finally()
方法的回調函數不接受任何的參數,也就是說你在.finally()
函數中是無法知道Promise
最終的狀態是resolved
仍是rejected
的
它最終返回的默認會是一個上一次的Promise對象值,不過若是拋出的是一個異常則返回異常的Promise
對象。
最後能夠說一下all
以及race
方法:
Promise.all()
的做用是接收一組異步任務,而後並行執行異步任務,而且在全部異步操做執行完後才執行回調。.race()
的做用也是接收一組異步任務,而後並行執行異步任務,只保留取第一個執行完成的異步操做的結果,其餘的方法仍在執行,不過執行結果會被拋棄。Promise.all().then()
結果中數組的順序和Promise.all()
接收到的數組順序一致。all和race
傳入的數組中若是有會拋出異常的異步任務,那麼只有最早拋出的錯誤會被捕獲,而且是被then
的第二個參數或者後面的catch
捕獲;但並不會影響數組中其它的異步任務的執行。這個,在上一題已經說到了:
all和race
傳入的數組中若是有會拋出異常的異步任務,那麼只有最早拋出的錯誤會被捕獲,而且是被then
的第二個參數或者後面的catch
捕獲;但並不會影響數組中其它的異步任務的執行。
因爲它的then
方法和catch、finally
方法會返回一個**新的Promise
**因此能夠容許咱們鏈式調用
一開始整個腳本做爲一個宏任務執行
執行過程當中同步代碼直接執行,宏任務進入宏任務隊列,微任務進入微任務隊列
當前宏任務執行完出隊,檢查微任務列表,有則依次執行,直到所有執行完
執行瀏覽器UI線程的渲染工做
檢查是否有Web Worker
任務,有則執行
執行完本輪的宏任務,回到2,依此循環,直到宏任務和微任務隊列都爲空
(具體能夠看這裏:juejin.im/post/5e58c6…
層級關係:
window > document > html > body
複製代碼
window
是BOM
的核心對象,它一方面用來獲取或設置瀏覽器的屬性和行爲,另外一方面做爲一個全局對象。document
對象是一個跟文檔相關的對象,擁有一些操做文檔內容的功能。可是地位沒有window
高。html
元素對象和document
元素對象是屬於html
文檔的DOM
對象,能夠認爲就是html
源代碼中那些標籤所化成的對象。他們跟div、select
什麼對象沒有根本區別。(我是這樣記的,整個瀏覽器中最大的確定就是窗口window
了,那麼進來的我無論你是啥,就算你是document
也得給我盤着)
第三個參數涉及到冒泡和捕獲,是true
時爲捕獲,是false
則爲冒泡
使用Event
使用customEvent
(能夠傳參數)
使用document.createEvent('CustomEvent')和initCustomEvent()
建立自定義事件
原生自定義事件有三種寫法:
Event
let myEvent = new Event('event_name');
複製代碼
customEvent
(能夠傳參數)let myEvent = new CustomEvent('event_name', {
detail: {
// 將須要傳遞的參數放到這裏
// 能夠在監聽的回調函數中獲取到:event.detail
}
})
複製代碼
document.createEvent('CustomEvent')和initCustomEvent()
let myEvent = document.createEvent('CustomEvent');// 注意這裏是爲'CustomEvent'
myEvent.initEvent(
// 1. event_name: 事件名稱
// 2. canBubble: 是否冒泡
// 3. cancelable: 是否能夠取消默認行爲
)
複製代碼
createEvent
:建立一個事件initEvent
:初始化一個事件能夠看到,initEvent
能夠指定3個參數。
(有些文章中會說還有第四個參數detail
,可是我查看了W3C
上並無這個參數,並且實踐了一下也沒有效果)
事件的監聽
自定義事件的監聽其實和普通事件的同樣,使用addEventListener
來監聽:
button.addEventListener('event_name', function (e) {})
複製代碼
事件的觸發
觸發自定義事件使用dispatchEvent(myEvent)
。
注意⚠️,這裏的參數是要自定義事件的對象(也就是myEvent
),而不是自定義事件的名稱('myEvent'
)
案例
來看個案例吧:
// 1.
// let myEvent = new Event('myEvent');
// 2.
// let myEvent = new CustomEvent('myEvent', {
// detail: {
// name: 'lindaidai'
// }
// })
// 3.
let myEvent = document.createEvent('CustomEvent');
myEvent.initEvent('myEvent', true, true)
let btn = document.getElementsByTagName('button')[0]
btn.addEventListener('myEvent', function (e) {
console.log(e)
console.log(e.detail)
})
setTimeout(() => {
btn.dispatchEvent(myEvent)
}, 2000)
複製代碼
冒泡指的是:當給某個目標元素綁定了事件以後,這個事件會依次在它的父級元素中被觸發(固然前提是這個父級元素也有這個同名稱的事件,好比子元素和父元素都綁定了click
事件就觸發父元素的click
)。
捕獲則是從上層向下層傳遞,與冒泡相反。
(很是好記,你就想一想水底有一個泡泡從下面往上傳的,因此是冒泡)
來看看這個例子:
<!-- 會依次執行 button li ul -->
<ul onclick="alert('ul')">
<li onclick="alert('li')">
<button onclick="alert('button')">點擊</button>
</li>
</ul>
<script> window.addEventListener('click', function (e) { alert('window') }) document.addEventListener('click', function (e) { alert('document') }) </script>
複製代碼
冒泡結果:button > li > ul > document > window
捕獲結果:window > document > ul > li > button
並非全部的事件都有冒泡的,例如如下事件就沒有:
onblur
onfocus
onmouseenter
onmouseleave
function myNew (fn, ...args) {
let instance = Object.create(fn.prototype);
let result = fn.call(instance, ...args)
return typeof result === 'object' ? result : instance;
}
複製代碼
typeof
表示是對某個變量類型的檢測,基本數據類型除了null
都能正常的顯示爲對應的類型,引用類型除了函數會顯示爲'function'
,其它都顯示爲object
。
而instanceof
它主要是用於檢測某個構造函數的原型對象在不在某個對象的原型鏈上。
這只是 JS 存在的一個悠久 Bug。在 JS 的最第一版本中使用的是 32 位系統,爲了性能考慮使用低位存儲變量的類型信息,000 開頭表明是對象然而 null 表示爲全零,因此將它錯誤的判斷爲 object 。
instanceof
它主要是用於檢測某個構造函數的原型對象在不在某個對象的原型鏈上。
算了,直接手寫實現吧:
function myInstanceof (left, right) {
let proto = Object.getPrototypeOf(left);
while (true) {
if (proto === null) return false;
if (proto === right.prototype) return true;
proto = Object.getPrototypeOf(proto)
}
}
複製代碼
指向最後調用函數的那個對象,是函數運行時內部自動生成的一個內部對象,只能在函數內部使用
函數調用時,指向最後調用的那個對象
(答案參考童歐巴的一篇webpack
面試文章哦:「吐血整理」再來一打Webpack面試題(持續更新))
loader它是一個轉換器,只專一於轉換文件這一個領域,完成壓縮、打包、語言編譯,它僅僅是爲了打包。而且運行在打包以前。
而plugin是一個擴展器,它豐富了webpack自己,爲其進行一些其它功能的擴展。它不侷限於打包,資源的加載,還有其它的功能。因此它是在整個編譯週期都起做用。
HTTP的責任是去定義數據,在兩臺計算機相互傳遞信息時,HTTP規定了每段數據以什麼形式表達纔是可以被另一臺計算機理解。
而TCP所要規定的是數據應該怎麼傳輸才能穩定且高效的傳遞與計算機之間。
(還能夠再擴展)
TCP爲何可靠,是由於它有三次握手來保證雙方都有接受和發送數據的能力。
字節流服務:將大塊數據分割爲以報文段爲單位的數據包進行管理
虛擬DOM
本質就是用一個原生的JavaScript
對象去描述一個DOM
節點。是對真實DOM
的一層抽象。
因爲在瀏覽器中操做DOM
是很昂貴的。頻繁的操做DOM
,會產生必定的性能問題,所以咱們須要這一層抽象,在patch
過程當中儘量地一次性將差別更新到DOM
中,這樣保證了DOM
不會出現性能不好的狀況。
另外還有很重要的一點,也是它的設計初衷,爲了更好的跨平臺,好比Node.js
就沒有DOM
,若是想實現SSR
(服務端渲染),那麼一個方式就是藉助Virtual DOM
,由於Virtual DOM
自己是JavaScript
對象。
Vue2.x
中的虛擬DOM
主要是借鑑了snabbdom.js
,Vue3
中借鑑inferno.js
算法進行優化。
看三元的《(1.6w字)瀏覽器靈魂之問,請問你能接得住幾個?》
分別從網絡,解析,渲染來講
面試的問題基本都答出來了,固然後面還有一個技術總監的電話面,主要是問了一些工做相關的問題。
其實這家公司開出的條件也挺讓呆呆心動的,包括氛圍感受也挺好,只不過可能還不是本身想要的吧,因此最終也是沒去,挺惋惜的...若是面試個人那位小哥哥哥看到了這裏,還請不要難過哈,咱們江湖會再見的😂。
4月27日
一面
並詳細說一下前面三道
(嘻嘻,這個是呆呆留給大家的題目,考考大家,就不寫答案了)
(實際上是呆呆當時只答出了前面三道😂)
二面
基本原理:主要就是利用 script
標籤的src
屬性沒有跨域的限制,經過指向一個須要訪問的地址,由服務端返回一個預先定義好的 Javascript
函數的調用,而且將服務器數據以該函數參數的形式傳遞過來,此方法須要先後端配合完成。
執行過程:
jsonpCallback = function (res) {}
)params
的形式包裝script
標籤的請求參數,而且聲明執行函數(如cb=jsonpCallback
)jsonpCallback
),並以帶上參數且調用執行函數的方式傳遞給前端script
標籤返回資源的時候就會去執行jsonpCallback
並經過回調函數的方式拿到數據了。缺點:
GET
請求優勢:
代碼實現:
(具體能夠看個人這篇文章:JSONP原理及實現)
<script> function JSONP({ url, params = {}, callbackKey = 'cb', callback }) { // 定義本地的惟一callbackId,如果沒有的話則初始化爲1 JSONP.callbackId = JSONP.callbackId || 1; let callbackId = JSONP.callbackId; // 把要執行的回調加入到JSON對象中,避免污染window JSONP.callbacks = JSONP.callbacks || []; JSONP.callbacks[callbackId] = callback; // 把這個名稱加入到參數中: 'cb=JSONP.callbacks[1]' params[callbackKey] = `JSONP.callbacks[${callbackId}]`; // 獲得'id=1&cb=JSONP.callbacks[1]' const paramString = Object.keys(params).map(key => { return `${key}=${encodeURIComponent(params[key])}` }).join('&') // 建立 script 標籤 const script = document.createElement('script'); script.setAttribute('src', `${url}?${paramString}`); document.body.appendChild(script); // id自增,保證惟一 JSONP.callbackId++; } JSONP({ url: 'http://localhost:8080/api/jsonps', params: { a: '2&b=3', b: '4' }, callbackKey: 'cb', callback (res) { console.log(res) } }) JSONP({ url: 'http://localhost:8080/api/jsonp', params: { id: 1 }, callbackKey: 'cb', callback (res) { console.log(res) } }) </script>
複製代碼
跨域的產生來源於現代瀏覽器所通用的同源策略
,所謂同源策略,是指只有在地址的:
均同樣的狀況下,才容許訪問相同的cookie、localStorage,以及訪問頁面的DOM
或是發送Ajax
請求。若在不一樣源的狀況下訪問,就稱爲跨域。
例如如下爲同源:
http://www.example.com:8080/index.html
http://www.example.com:8080/home.html
複製代碼
如下爲跨域:
http://www.example.com:8080/index.html
http://www3.example.com:8080/index.html
複製代碼
注意⚠️:
可是有兩種狀況:http
默認的端口號爲80
,https
默認端口號爲443
。
因此:
http://www.example.com:80 === http://www.example.com
https://www.example.com:443 === https://www.example.com
複製代碼
爲何瀏覽器會禁止跨域?
簡答:
首先,跨域只存在於瀏覽器端,由於咱們知道瀏覽器的形態是很開放的,因此咱們須要對它有所限制。
其次,同源策略主要是爲了保證用戶信息的安全,可分爲兩種:Ajax
同源策略和DOM
同源策略。
Ajax
同源策略主要是使得不一樣源的頁面不能獲取cookie
且不能發起Ajax
請求,這樣在必定層度上防止了CSRF
攻擊。
DOM
同源策略也同樣,它限制了不一樣源頁面不能獲取DOM
,這樣能夠防止一些惡意網站在本身的網站中利用iframe
嵌入正規的網站並迷惑用戶,以此來達到竊取用戶信息。
深答:
首先,跨域只存在於瀏覽器端。瀏覽器它爲web
提供了訪問入口,而且訪問的方式很簡單,在地址欄輸入要訪問的地址或者點擊某個連接就能夠了,正是這種開放的形態,因此咱們須要對它有所限制。
因此同源策略它的產生主要是爲了保證用戶信息的安全,防止惡意的網站竊取數據。分爲兩種:Ajax
同源策略與DOM
同源策略:
Ajax
同源策略它主要作了這兩種限制:1.不一樣源頁面不能獲取cookie
;2.不一樣源頁面不能發起Ajax
請求。我認爲它是防止CSRF
攻擊的一種方式吧。由於咱們知道cookie
這個東西它主要是爲了解決瀏覽器與服務器會話狀態的問題,它本質上是存儲在瀏覽器或本地文件中一個小小的文本文件,那麼它裏面通常都會存儲了用戶的一些信息,包括隱私信息。若是沒有Ajax
同源策略,惡意網站只須要一段腳本就能夠獲取你的cookie
,從而冒充你的身份去給其它網站發送惡意的請求。DOM
同源策略也同樣,它限制了不一樣源頁面不能獲取DOM
。例如一個假的網站利用iframe
嵌套了一個銀行網站mybank.com,並把寬高或者其它部分調整的和原銀行網站同樣,僅僅只是地址欄上的域名不一樣,如果用戶沒有注意的話就覺得這個是個真的網站。若是這時候用戶在裏面輸入了帳號密碼,若是沒有同源策略,那麼這個惡意網站就能夠獲取到銀行網站中的DOM
,也就能拿到用戶的輸入內容以此來達到竊取用戶信息的攻擊。同源策略它算是瀏覽器安全的第一層屏障吧,由於就像CSRF
攻擊,它只能限制不一樣源頁面cookie
的獲取,可是攻擊者還可能經過其它的方式來達到攻擊效果。
(注,上面提到的iframe
限制DOM
查詢,案例以下)
// HTML
<iframe name="yinhang" src="www.yinhang.com"></iframe>
// JS
// 因爲沒有同源策略的限制,釣魚網站能夠直接拿到別的網站的Dom
const iframe = window.frames['yinhang']
const node = iframe.document.getElementById('你輸入帳號密碼的Input')
console.log(`拿到了這個${node},我還拿不到你剛剛輸入的帳號密碼嗎`)
複製代碼
參考:
跨域資源共享(CORS
)是一種機制,是W3C標準。它容許瀏覽器向跨源服務器,發出XMLHttpRequest
或Fetch
請求。而且整個CORS
通訊過程都是瀏覽器自動完成的,不須要用戶參與。
而使用這種跨域資源共享
的前提是,瀏覽器必須支持這個功能,而且服務器端也必須贊成這種"跨域"
請求。所以實現CORS
的關鍵是服務器須要服務器。一般是有如下幾個配置:
具體可看:developer.mozilla.org/zh-CN/docs/…
過程分析:
簡單回答:
當咱們發起跨域請求時,若是是非簡單請求,瀏覽器會幫咱們自動觸發預檢請求,也就是 OPTIONS 請求,用於確認目標資源是否支持跨域。若是是簡單請求,則不會觸發預檢,直接發出正常請求。
瀏覽器會根據服務端響應的 header 自動處理剩餘的請求,若是響應支持跨域,則繼續發出正常請求,若是不支持,則在控制檯顯示錯誤。
詳細回答:
瀏覽器先根據同源策略對前端頁面和後臺交互地址作匹配,若同源,則直接發送數據請求;若不一樣源,則發送跨域請求。
服務器收到瀏覽器跨域請求後,根據自身配置返回對應文件頭。若未配置過任何容許跨域,則文件頭裏不包含 Access-Control-Allow-origin
字段,若配置過域名,則返回 Access-Control-Allow-origin + 對應配置規則裏的域名的方式
。
瀏覽器根據接受到的 響應頭裏的 Access-Control-Allow-origin
字段作匹配,若無該字段,說明不容許跨域,從而拋出一個錯誤;如有該字段,則對字段內容和當前域名作比對,若是同源,則說明能夠跨域,瀏覽器接受該響應;若不一樣源,則說明該域名不可跨域,瀏覽器不接受該響應,並拋出一個錯誤。
在CORS
中有簡單請求
和非簡單請求
,簡單請求是不會觸發CORS
的預檢請求的,而非簡單請求會。
「需預檢的請求」
要求必須首先使用 OPTIONS
方法發起一個預檢請求到服務器,以獲知服務器是否容許該實際請求。"預檢請求「的使用,能夠避免跨域請求對服務器的用戶數據產生未預期的影響。
(關於更多CORS的內容能夠看個人另外一篇文章:CORS原理及實現)
這個當時面試官和我說的是,中間會通過不少的站點,好比會通過湖南,或者其它城市,由各個城市的這些站點一層一層分發下去。
面的最慘的一次...由於此次面試是當天下午6點纔去面的,在這以前呆呆已經通過了3輪面試的折磨,因此身心疲憊很不在狀態。固然最主要的是本身確實準備的還不夠充分,其實如今回過頭來看看這些題都不太難的...
當天也小小的自閉了一下,整理好狀態次日好好總結吧 😄。
4月28日
(當時是電話面,一個小時20分鐘,問了我大概五六十道題,我能想到的一共是50題,還有一些記不起來了)
require()
方法;而ES6 Modules只能是字符串this
指向當前模塊,ES6 Modules this
指向undefined
arguments
、require
、module
、exports
、__filename
、__dirname
關於第一個差別,是由於CommonJS 加載的是一個對象(即module.exports
屬性),該對象只有在腳本運行完纔會生成。而 ES6 模塊不是對象,它的對外接口只是一種靜態定義,在代碼靜態解析階段就會生成。
(具體能夠看個人這篇文章:juejin.im/post/5eaacd…
模塊的異步加載可使用AMD
或者CMD
規範。
(具體能夠看個人這篇文章:juejin.im/post/5eaacd…
封閉開放式原則、安全性
(應該還有,可是沒想到)
reduce
,初始值傳入一個Promise.resolve()
,以後往裏面不停的疊加.then()
。(相似於這裏https://juejin.im/post/5e58c618e51d4526ed66b5cf#heading-51)forEach
,本質和reduce
原理相同。(相似於這裏https://juejin.im/post/5e58c618e51d4526ed66b5cf#heading-53)ES9
中的for...await...of
來實現。併發的。不過Promise.all().then()
結果中數組的順序和Promise.all()
接收到的數組順序一致。
var trimReg = /(^\s+)|(\s+$)/g
;不事後來因爲Vue
中有一個修飾符.trim
,使用起來更方便(如v-model.trim="msg"
)就用這種方式多一些;再或者也能夠用ES10
新出的trimStart
和trimEnd
來去除首尾空格。var phoneReg = /^1[3456789]\d{9}$/g
。function getCookie(name) {
var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]*)'));
if (match) return unescape(match[2]);
}
複製代碼
(詳細介紹能夠看這裏:每日一題-JS篇-根據name獲取cookie中值的方法)
^
要是放在[]
裏的話就表示"除了^後面的內容都能匹配"
,也就是非的意思。
例如:
(除了l
,其它都變成了"帥"
)
var str = 'lindaidai';
console.log(str.replace(/[^l]/g, '帥'));
// l帥帥帥帥帥帥帥帥
複製代碼
反之,若是是不在[]
裏的話則表示開頭匹配:
(只有l
變成了"帥"
)
var str = 'lindaidai';
console.log(str.replace(/^l/g, '帥'));
複製代碼
hash
是跟整個項目的構建相關,只要項目裏有文件更改,整個項目構建的hash
值都會更改,而且所有文件都共用相同的hash
值。(粒度整個項目)chunkhash
是根據不一樣的入口進行依賴文件解析,構建對應的chunk
(模塊),生成對應的hash
值。只有被修改的chunk
(模塊)在從新構建以後纔會生成新的hash
值,不會影響其它的chunk
。(粒度entry
的每一個入口文件)contenthash
是跟每一個生成的文件有關,每一個文件都有一個惟一的hash
值。當要構建的文件內容發生改變時,就會生成新的hash
值,且該文件的改變並不會影響和它同一個模塊下的其它文件。(粒度每一個文件的內容)(具體能夠看我簡書上的這篇文章:www.jianshu.com/p/486453d81…
這裏只是說明了三種hash
的不一樣...至於原理暫時沒了解。
這個問題在上一個問題中已經說明了,要看webpack
的配置。
有三種狀況:
hash
的話,是和整個項目有關的,有一處文件發生更改則全部文件的hash
值都會發生改變且它們共用一個hash
值;chunkhash
的話,只和entry
的每一個入口文件有關,也就是同一個chunk
下的文件有所改動該chunk
下的文件的hash
值就會發生改變contenthash
的話,和每一個生成的文件有關,只有當要構建的文件內容發生改變時纔會給該文件生成新的hash
值,並不會影響其它文件。在webpack
中有兩種處理圖片的loader
:
file-loader
:解決CSS
等中引入圖片的路徑問題;(解決經過url
,import/require()
等引入圖片的問題)url-loader
:當圖片小於設置的limit
參數值時,url-loader
將圖片進行base64
編碼(當項目中有不少圖片,經過url-loader
進行base64
編碼後會減小http
請求數量,提升性能),大於limit參數值,則使用file-loader
拷貝圖片並輸出到編譯目錄中;(詳細使用能夠查看這裏:霖呆呆的webpack之路-loader篇)
迴流:
觸發條件:
當咱們對 DOM 結構的修改引起 DOM 幾何尺寸變化的時候,會發生迴流
的過程。
例如如下操做會觸發迴流:
一個 DOM 元素的幾何屬性變化,常見的幾何屬性有width
、height
、padding
、margin
、left
、top
、border
等等, 這個很好理解。
使 DOM 節點發生增減
或者移動
。
讀寫 offset
族、scroll
族和client
族屬性的時候,瀏覽器爲了獲取這些值,須要進行迴流操做。
調用 window.getComputedStyle
方法。
迴流過程:因爲DOM的結構發生了改變,因此須要從生成DOM這一步開始,從新通過樣式計算
、生成佈局樹
、創建圖層樹
、再到生成繪製列表
以及以後的顯示器顯示這整一個渲染過程走一遍,開銷是很是大的。
重繪:
觸發條件:
當 DOM 的修改致使了樣式的變化,而且沒有影響幾何屬性的時候,會致使重繪
(repaint
)。
重繪過程:因爲沒有致使 DOM 幾何屬性的變化,所以元素的位置信息不須要更新,因此當發生重繪的時候,會跳過生存佈局樹
和創建圖層樹
的階段,直接到生成繪製列表
,而後繼續進行分塊、生成位圖等後面一系列操做。
如何避免觸發迴流和重繪:
class
的方式。position
屬性爲absolute
或fixed
的元素上。display: none
,操做結束後再把它顯示出來。由於在display
屬性爲none
的元素上進行的DOM操做不會引起迴流和重繪createDocumentFragment
進行批量的 DOM 操做。transform
、opacity
、filter
這些屬性能夠實現合成的效果,也就是CPU
加速。box-sizing: content-box
(W3C盒模型,又名標準盒模型):元素的寬高大小表現爲內容的大小。
box-sizing: border-box
(IE盒模型,又名怪異盒模型):元素的寬高表現爲內容 + 內邊距 + 邊框的大小。背景會延伸到邊框的外沿。
這裏我是按照子弈的總結答的: juejin.im/post/5d690c…
.box {
display: flex;
width: 100px;
height: 100px;
background-color: pink;
}
.box-center{
margin: auto;
background-color: greenyellow;
}
複製代碼
.box {
display: flex;
width: 100px;
height: 100px;
background-color: pink;
justify-content: center;
align-items: center;
}
.box-center{
background-color: greenyellow;
}
複製代碼
.box {
position: relative;
height: 100px;
width: 100px;
background-color: pink;
}
.box-center{
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
margin: auto;
width: 50px;
height: 50px;
background-color: greenyellow;
}
複製代碼
簡單回答:
IE6~9
不支持,IE10~11
部分支持flex的2012版
,可是須要-ms-
前綴。
其它的主流瀏覽器包括安卓和IOS
基本上都支持了。
詳細回答:
能夠到Can I use
上去查看,官網地址爲:caniuse.com/
比較經常使用的:
em
:定義字體大小時以父級的字體大小爲基準;定義長度單位時以當前字體大小爲基準。例父級font-size: 14px
,則子級font-size: 1em;
爲font-size: 14px;
;若定義長度時,子級的字體大小若是爲14px
,則子級width: 2em;
爲width: 24px
。rem
:以根元素的字體大小爲基準。例如html
的font-size: 14px
,則子級1rem = 14px
。%
:以父級的寬度爲基準。例父級width: 200px
,則子級width: 50%;height:50%;
爲width: 100px;height: 100px;
vw和vh
:基於視口的寬度和高度(視口不包括瀏覽器的地址欄工具欄和狀態欄)。例如視口寬度爲1000px
,則60vw = 600px;
vmin和vmax
:vmin
爲當前vw
和vh
中較小的一個值;vmax
爲較大的一個值。例如視口寬度375px
,視口高度812px
,則100vmin = 375px;
,100vmax = 812px;
不經常使用的:
ex和ch
:ex
以字符"x"
的高度爲基準;例如1ex
表示和字符"x"
同樣長。ch
以數字"0"
的寬度爲基準;例如2ch
表示和2個數字"0"
同樣長。移動端佈局總結:
(總結來源:玲瓏)
em:
定義字體大小時以父級的字體大小爲基準;定義長度單位時以當前字體大小爲基準。例父級font-size: 14px
,則子級font-size: 1em;
爲font-size: 14px;
;若定義長度時,子級的字體大小若是爲14px
,則子級width: 2em;
爲width: 24px
。
rem:
以根元素的字體大小爲基準。例如html
的font-size: 14px
,則子級1rem = 14px
。
一個簡易版的初始化根元素字體大小。
頁面開頭處引入下面這段代碼,用於動態計算font-size
:
(假設你須要的1rem = 20px
)
(function () {
var html = document.documentElement;
function onWindowResize() {
html.style.fontSize = html.getBoundingClientRect().width / 20 + 'px';
}
window.addEventListener('resize', onWindowResize);
onWindowResize();
})();
複製代碼
document.documentElement
:獲取document
的根元素html.getBoundingClientRect().width
:獲取html
的寬度(窗口的寬度)window
的resize
事件通常還須要配合一個meta
頭:
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-sacle=1.0, maximum-scale=1.0, user-scalable=no" />
複製代碼
若是沒有人爲取改變根元素字體大小的話,默認是1rem = 16px
;根元素默認的字體大小是16px
。
實話實說沒太作過。
css代碼:
<style> .box { width: 100px; height: 100px; background-color: red; animation: spin 2s linear infinite; } @keyframes spin { from { transform: rotate(0deg) } to { transform: rotate(360deg) } } </style>
複製代碼
html代碼:
<div class="box"></div>
複製代碼
語法:
animation: name duration timing-function delay iteration-count direction;
複製代碼
值 | 描述 |
---|---|
animation-name | 規定須要綁定到選擇器的 keyframe 名稱。(mymove) |
animation-duration | 規定完成動畫所花費的時間,以秒或毫秒計。(2s) |
animation-timing-function | 規定動畫的速度曲線。(ease|linear|ease-in|cubic-bezier(n,n,n,n)) |
animation-delay | 規定在動畫開始以前的延遲。(2s) |
animation-iteration-count | 規定動畫應該播放的次數。(n | infinite) n次/無限 |
animation-direction | 規定是否應該輪流反向播放動畫。(normal | alternate) 正常/反向 |
一句話介紹:steps()
功能符可讓動畫不連續。
地位和做用:和貝塞爾曲線(cubic-bezier()
修飾符)同樣,均可以做爲animation
的第三個屬性值。
和貝塞爾曲線的區別:貝塞爾曲線像是滑梯且有4個關鍵字(參數),而steps
像是樓梯坡道且只有number
和position
兩個關鍵字。
語法:
steps(number, position)
複製代碼
start
和end
兩個關鍵字,含義分別以下:
start
:表示直接開始。end
:表示戛然而止。是默認值。具體能夠看這裏:www.zhangxinxu.com/wordpress/2…
Chrome
瀏覽器 -> more tools
-> Remote devices
-> chrome://inspect/#devices
Mac
+ IOS
+ Safari
V8引擎幫助咱們實現了自動的垃圾回收管理,利用瀏覽器渲染頁面的空閒時間進行垃圾回收。
(這裏我用的是:juejin.im/post/5e8b26… 裏的總結)
棧內存的回收:
棧內存調用棧上下文切換後就被回收,比較簡單。
堆內存的回收:
V8的堆內存分爲新生代內存和老生代內存,新生代內存是臨時分配的內存,存在時間短,老生代內存存在時間長。
新生代內存回收機制:
老生代內存回收機制
(固然想要詳細瞭解的話也能夠看個人這篇文章:JavaScript進階-內存機制(表情包初探))
因爲我在項目中是會對axios
作一層封裝,因此每次請求的域名也是寫在配置文件中,有一個baseURL
字段專門用於存儲它,因此只要改這個字段就能夠達到替換全部請求http
爲https
了。
固然後面我也有了解到:
利用meta
標籤把http
請求換爲https
:
<meta http-equiv ="Content-Security-Policy" content="upgrade-insecure-requests">
複製代碼
參考上一題👆。
在瀏覽器和服務器進行傳輸的時候,能夠被nginx
代理所攔截,也能夠被網關攔截。
HTTPS主要是採用對稱密鑰加密和非對稱密鑰加密組合而成的混合加密機制進行傳輸。
也就是發送密文的一方用"對方的公鑰"進行加密處理"對稱的密鑰",而後對方在收到以後使用本身的私鑰進行解密獲得"對稱的密鑰",這在確保雙發交換的密鑰是安全的前提下使用對稱密鑰方式進行通訊。
對稱密鑰加密和非對稱密鑰加密都有它們各類的優缺點,而混合加密機制就是將二者結合利用它們各自的優勢來進行加密傳輸。
好比既然對稱密鑰的優勢是加解密效率快,那麼在客戶端與服務端肯定了鏈接以後就能夠用它來進行加密傳輸。不過前提是得解決雙方都能安全的拿到這把對稱密鑰。這時候就能夠利用非對稱密鑰加密來傳輸這把對稱密鑰,由於咱們知道非對稱密鑰加密的優勢就是能保證傳輸的內容是安全的。
因此它的好處是即保證了對稱密鑰能在雙方之間安全的傳輸,又能使用對稱加密方式進行通訊,這比單純的使用非對稱加密通訊快了不少。以此來解決了HTTP中內容可能被竊聽的問題。
其它HTTP相關的問題:
如:
HTTPS的工做流程
混合加密機制的好處
數字簽名
ECDHE握手和RSA握手
向前安全性
這些問題均可以看到個人這篇文章:HTTPS面試問答
這道題主要能夠從數字簽名
和數字證書
上來答。
當時我答的時候就把證書的頒發流程
、HTTPS
數字證書的驗證過程完整的說了一遍就算過了。
具體能夠看HTTPS面試問答中的第五、六、7
問。
這個無非就是配合If-None-Match
來達到一個協商緩存
的做用。值爲服務器某個資源的惟一標識。
具體能夠看個人這篇文章:霖呆呆你來講說瀏覽器緩存吧
Token
其實就是訪問資源的憑證。
通常是用戶經過用戶名和密碼登陸成功以後,服務器將登錄憑證作數字簽名,加密以後獲得的字符串做爲token
。
它在用戶登陸成功以後會返回給客戶端,客戶端主要有這麼幾種存儲方式:
localStorage
中,每次調用接口的時候都把它當成一個字段傳給後臺cookie
中,讓它自動發送,不過缺點就是不能跨域localStorage
中,每次調用接口的時候放在HTTP
請求頭的Authorization
字段裏(很明顯我答的不夠專業,歡迎補充,感謝😊)
(很明顯我答的不夠專業,歡迎補充,感謝😊)
用戶登陸成功以後的一些信息
(很明顯我答的不夠專業,歡迎補充,感謝😊)
(很明顯我答的不夠專業,歡迎補充,感謝😊)
(很明顯我答的不夠專業,歡迎補充,感謝😊)
只會配置一些跨域方面的問題。
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://localhost:8887;
add_header Access-Control-Allow-Origin *;
}
}
}
複製代碼
利用ngnix跨域的關鍵就是在配置文件中設置server
項,而後設置其中的location
屬性,proxy_pass
:須要代理的服務器地址,add_header:給響應報文中添加首部字段,例如Access-Control-Allow-Origin
設置爲*
,即容許全部的請求源請求。
具體能夠看:Yiming君-面試題:nginx有配置過嗎?反向代理知道嗎?
咱們將請求發送到服務器,而後服務器對咱們的請求進行轉發,咱們只須要和代理服務器進行通訊就好。因此對於客戶端來講,是感知不到服務器的。
唔...沒有...
(...默默的點頭)
唔...知道...
這裏我是按照:
中的第13題答的。
放在methods
中,由於computed
會有惰性,並不能知道new Date()
的改變。
小小的寫了一篇文章,能夠看這裏:數據權限如何控制
和麪試官扯了一堆我數據權限判斷的具體過程,其中可能有多個權限:並的狀況000011110001&000011110002
,或的狀況000011110001|000011110002
,以及如何作的權限匹配。最後面試官:
"因此那仍是用的字符串匹配咯?"
尬...我比較low
...用的字符串匹配...
(哇,真的絕了...1個小時20分鐘50多道題,答的我口渴😂,不過也能夠看出有不少移動端的我都沒有答上來,面試官也表示理解,畢竟我主要是以PC端爲主,因此居然也算是過了,很感謝這位面試官細心的幫我分析一些問題)
後來有了解這位面試官近期也跳槽去騰訊了,果真面完呆呆以後他就去大廠了,好人一輩子平安😂🙏。
這家公司實際上是上家公司的總部,由於面完上家以後,HR也知道個人顧慮,想要去一個大點的團隊,因此就把我推薦去了他們的總部。很是Nice的HR小姐姐,好感動,就算你看不到個人文章,我也仍是要感謝你 😂。
5月8日
一面(前端副總監)
(必問...)
看三元的《(1.6w字)瀏覽器靈魂之問,請問你能接得住幾個?》
分別從網絡,解析,渲染來講
JS
代碼在加載完以後是當即執行的,且JS
代碼執行時會阻塞頁面的渲染。
JS屬於單線程,當咱們在加載script
標籤內容的時候,渲染線程會被暫停,由於script
標籤裏可能會操做DOM
的,因此若是你加載script
標籤又同時渲染頁面確定就衝突了,所以說渲染線程(GUI
)和js引擎線程互斥。
Last-Modefied
配合If-Modified-Since
ETag
配合If-None-Match
也是個常見的問題了,不瞭解的小夥伴能夠看個人這篇文章:霖呆呆你來講說瀏覽器緩存吧
(當時面試官還重複了一下我說的這4個頭部字段,本身回顧了一下我說的對不對,好可愛~)
Keep-Alive
是HTTP
的一個頭部字段Connection
中的一個值,它是保證咱們的HTTP
請求能創建一個持久鏈接。也就是說創建一次TCP
鏈接便可進行屢次請求和響應的交互。它的特色就是隻要有一方沒有明確的提出斷開鏈接,則保持TCP
鏈接狀態,減小了TCP
鏈接和斷開形成的額外開銷。
另外,在HTTP/1.1
中全部的鏈接默認都是持久鏈接的,可是HTTP/1.0
並未標準化。
我工做中碰到主要是利用CORS
來解決跨域問題,說了一下它的原理以及後臺須要如何作。
另外說到了JSONP
的原理,以及它的優勢:兼容性好;缺點:只能進行GET
請求,且有安全問題。
還有說到了ngnix
反向代理來解決跨域。
其它的,我當時說我有看過一篇文章裏面詳細的介紹10多種跨域解決方案,可是本身沒有過多的去了解。
哈哈,其實也就是秋風大大的這篇文章10種跨域解決方案(附終極大招)
這個當時答的沒用過。
我知道它是能使得客戶端和服務器之間存在持久的鏈接,並且雙方均可以隨時開始發送數據,這種方式本質沒有使用 HTTP 的響應頭,所以也沒有跨域的限制。
(多的不會了)
(必問...)
(如下回答參考子弈小哥哥的面試分享:兩年工做經驗成功面試阿里P6總結
以及蔡徐坤小哥哥的2萬字 | 前端基礎拾遺90問)
XSS
XSS(Cross Site Script)跨站腳本攻擊。指的是攻擊者向網頁注入惡意的客戶端代碼,經過惡意的腳本對客戶端網頁進行篡改,從而在用戶瀏覽網頁時,對用戶瀏覽器進行控制或者獲取用戶隱私數據的一種攻擊方式。
主要是分爲三種:
存儲型:即攻擊被存儲在服務端,常見的是在評論區插入攻擊腳本,若是腳本被儲存到服務端,那麼全部看見對應評論的用戶都會受到攻擊。
反射型:攻擊者將腳本混在URL裏,服務端接收到URL將惡意代碼當作參數取出並拼接在HTML裏返回,瀏覽器解析此HTML後即執行惡意代碼
DOM型:將攻擊腳本寫在URL中,誘導用戶點擊該URL,若是URL被解析,那麼攻擊腳本就會被運行。和前二者的差異主要在於DOM型攻擊不通過服務端
如何防護XSS攻擊
script
和<iframe>
等標籤進行轉義或者過濾CSRF
CSRF攻擊(Cross-site request forgery)跨站請求僞造。是一種劫持受信任用戶向服務器發送非預期請求的攻擊方式,一般狀況下,它是攻擊者藉助受害者的 Cookie 騙取服務器的信任,可是它並不能拿到Cookie,也看不到Cookie的內容,它能作的就是給服務器發送請求,而後執行請求中所描述的命令,以此來改變服務器中的數據,也就是並不能竊取服務器中的數據。
防護主要有三種:
驗證Token
:瀏覽器請求服務器時,服務器返回一個token,每一個請求都須要同時帶上token和cookie纔會被認爲是合法請求
驗證Referer
:經過驗證請求頭的Referer來驗證來源站點,但請求頭很容易僞造
設置SameSite
:設置cookie的SameSite,可讓cookie不隨跨站請求發出,但瀏覽器兼容不一
點擊挾持
預防策略:
top.location.hostname === self.location.hostname
;(這個來源於LuckyWinty: www.imooc.com/article/295…)
(必問...)
(回答參考:juejin.im/post/5e621f…)
setTimeout
的運行機制:執行該語句時,是當即把當前定時器代碼推入事件隊列,當定時器在事件列表中知足設置的時間值時將傳入的函數加入任務隊列,以後的執行就交給任務隊列負責。可是若是此時任務隊列不爲空,則需等待,因此執行定時器內代碼的時間可能會大於設置的時間
說了一下它屬於異步任務,而後說了一下還有哪些宏任務以及微任務,最後說了一下EventLoop
的執行過程。
一開始整個腳本做爲一個宏任務執行
執行過程當中同步代碼直接執行,宏任務進入宏任務隊列,微任務進入微任務隊列
當前宏任務執行完出隊,檢查微任務列表,有則依次執行,直到所有執行完
執行瀏覽器UI線程的渲染工做
檢查是否有Web Worker
任務,有則執行
執行完本輪的宏任務,回到2,依此循環,直到宏任務和微任務隊列都爲空
(具體能夠看這裏:juejin.im/post/5e58c6…
(啪啪啪,不長記性,其實以前面試有被問過,可是忘了再去了解了,這就吃虧了,沒答上來)
requestAnimationFrame
是瀏覽器用於定時循環操做的一個接口,相似於setTimeout
,主要用途是按幀對網頁進行重繪。對於JS
動畫,用requestAnimationFrame
會比 setInterval
效果更好。
具體能夠看:juejin.im/post/5e621f…
同上...
(下面看着不少,但我確定不是全答哈,挑了幾個來回答)
ES6
:
Class
模塊import
和export
箭頭函數
函數默認參數
...
擴展運輸符容許展開數組
解構
字符串模版
Promise
let const
Proxy、Map、Set
對象屬性同名能簡寫
ES7
:
includes
**
求冪運算符
ES8
:
async/await
Object.values()和Object.entries()
padStart()和padEnd()
Object.getOwnPropertyDescriptors()
,
ES9
:
for...await...of
...
展開符合容許展開對象收集剩餘參數Promise.finally()
ES10
:
flat()
flatMap()
fromEntries()
trimStart
和trimEnd
matchAll
BigInt
try/catch
中報錯容許沒有err
異常參數Symbol.prototype.description
Function.toString()
調用時呈現本來源碼的樣子(還不瞭解的小夥伴能夠看看浪裏哥的這篇:盤點ES七、ES八、ES九、ES10新特性)
實話實話沒作過,可是後來面試官告訴我:可使用canvas
來實現。具體作法等我寫篇文章哈。
(當時我還反問了一句面試官:那批量圖片壓縮要怎麼作呢?把他驚的...而後他和我說挺複雜的...)
1個前端(我),1個小程序老哥(IOS轉行的),6個後臺。
例舉了我最經典的bpmn.js
,以此來引出我寫了不少關於這方面的教材,以及創建了微信羣,爲國內的bpmn.js
社區貢獻了一份力量...怎麼高大上怎麼來...
固然也有提到我GitHub
上的bpmn-chinese-document
項目只有100
多的Star
,他說理解,畢竟這東西用的人不是不少。
喊了個挺高的數,老哥笑了笑,你這個工做年限咱們可能給不到,而後扯了點別的。
(其實後面這些問題應該是等到HR面的時候問的,可是感受和麪試官挺聊的來的我就先打聽了)
二面(CTO)
絕了...又來
絕了...又來X2
當時答的是是用import
來按需引入,以及提到了Vue.use
。
但後來有去了解,babel-plugin-import
就能夠實現。
估計面試官看錯了...雖然個人項目有個組件庫的功能,可是是基於Ant Design of Vue
二次開發的。
沒了...
三面(HR)
問的問題有點多,我挑一些記得住的哈
(還有不少大佬的不少好文,不是呆呆不寫在這裏啊,是由於呆呆暫時只刷了這些,抱歉了😂)
你盼世界,我盼望你無bug
。這篇文章就介紹到了這裏。
有總結的不足的地方還喜歡小夥伴能在評論區留言。
我是一隻正在努力求生存的呆呆,也在這條路上不斷的總結和成長,但願本身可以堅持✊。
"風浪沒平息 我宣告奔跑的意義"
"這不是叛逆 我只是淋了一場雨"
喜歡霖呆呆的小夥還但願能夠關注霖呆呆的公衆號 LinDaiDai
或者掃一掃下面的二維碼👇👇👇.
我會不定時的更新一些前端方面的知識內容以及本身的原創文章🎉
你的鼓勵就是我持續創做的主要動力 😊.
相關推薦:
《【建議星星】要就來45道Promise面試題一次爽到底(1.1w字用心整理)》
《【建議👍】再來40道this面試題酸爽繼續(1.2w字用手整理)》
《【何不三連】比繼承家業還要簡單的JS繼承題-封裝篇(牛刀小試)》