從面試官角度看一次前端面試經(jīng)歷(6 個(gè)考察點(diǎn))
今天被抓差給候選者進(jìn)行初面。在這里記錄一下面試中涉及的幾個(gè)知識(shí)點(diǎn)。
每次面試我都會(huì)遞給候選者一瓶水,這樣可以讓候選者沒(méi)那么緊張,有更好的狀態(tài)進(jìn)行面試,畢竟面試是雙向選擇,公司也需要盡快找到合適的人,沒(méi)那么多網(wǎng)上說(shuō)的心理戰(zhàn)。
這里我還想吐槽一下面試造火箭工作擰螺絲,尤其是開(kāi)發(fā)行業(yè),很多面試官針對(duì)自己擅長(zhǎng)的方向大問(wèn)特問(wèn),完全忽略了候選人的優(yōu)勢(shì),從而給候選人帶來(lái)一個(gè)極差的面試體驗(yàn)。面試最好還是要通過(guò)候選人身上的優(yōu)點(diǎn)來(lái)判斷對(duì)方是否適合加入你的團(tuán)隊(duì)。
正常的面試應(yīng)該是按照候選人簡(jiǎn)歷中涉及的技術(shù)點(diǎn)發(fā)問(wèn),不然面試時(shí)給你一份簡(jiǎn)歷干嘛,至于簡(jiǎn)歷中未涉及的知識(shí)點(diǎn)有沒(méi)有必要問(wèn),我覺(jué)得沒(méi)什么必要的,因?yàn)楹芏嗳嗽趯?xiě)簡(jiǎn)歷的時(shí)候都是力求全面,恨不得聽(tīng)說(shuō)過(guò)的知識(shí)點(diǎn)都寫(xiě)上熟悉。所以按照簡(jiǎn)歷提問(wèn)就可以了。除此之外再問(wèn)一些最近流行的技術(shù),主要考察的是候選人對(duì)新技術(shù)的敏感性和對(duì)新事物的接受能力。
如果其中涉及到候選人回答不上的問(wèn)題也需要給候選人做一番解答,畢竟人家那么遠(yuǎn)來(lái)你這面試,總要有所收獲不是。
最后在簡(jiǎn)歷中挑選一個(gè)候選人比較擅長(zhǎng)的點(diǎn)深入來(lái)問(wèn),這個(gè)環(huán)節(jié)我一般稱(chēng)為定級(jí),前面的問(wèn)題如果回答的不錯(cuò),這個(gè)人基本就通過(guò)了,到最后就要給人定級(jí)。如果前面問(wèn)題回答的不理想基本也到不了這個(gè)環(huán)節(jié)。
Proxy
在2020年來(lái)看Proxy早已經(jīng)不是一個(gè)陌生的詞了,他能做的是有很多,尤其在Vue3.0通過(guò)Proxy來(lái)重構(gòu)之后,很多面試官喜歡問(wèn)這個(gè)Proxy以及和Object.defineProperty的對(duì)比。
Proxy是專(zhuān)門(mén)為對(duì)象設(shè)置訪問(wèn)代理器的,通過(guò)Proxy可以輕松監(jiān)視到對(duì)象的讀寫(xiě)過(guò)程,相比于defineProperty,Proxy他的功能要更為強(qiáng)大甚至使用起來(lái)也更為方便。
這里我們定義一個(gè)person對(duì)象,我們通過(guò)new Proxy的方式來(lái)去為我們的person來(lái)創(chuàng)建一個(gè)代理對(duì)象。
Proxy構(gòu)造函數(shù)的第一個(gè)參數(shù)就是我們需要代理的對(duì)象,這里是person,第二個(gè)參數(shù)也是一個(gè)對(duì)象,我們可以把這個(gè)對(duì)象稱(chēng)之為代理的處理對(duì)象,這個(gè)對(duì)象中可以通過(guò)get方法來(lái)去監(jiān)視屬性的訪問(wèn),通過(guò)set方法來(lái)去介紹對(duì)象當(dāng)中設(shè)置屬性這樣的一個(gè)過(guò)程。
const?person?=?{
????name:?'yd',
????age:?18
}
const?personProxy?=?new?Proxy(person,?{
????get()?{},
????set()?{}
})
先來(lái)看get方法,這個(gè)方法最簡(jiǎn)單可以接收兩個(gè)參數(shù),第一個(gè)就是所代理的目標(biāo)對(duì)象,第二個(gè)就是外部所訪問(wèn)的這個(gè)屬性的屬性名。這個(gè)方法的返回值將會(huì)作為外部去訪問(wèn)這個(gè)屬性得到的結(jié)果。
{
????get(target,?property)?{
????????console.log(target,?property);
????????return?property?in?target???target[property]?:?undefined;
????}
}
再來(lái)看下set方法,這個(gè)方法默認(rèn)接收三個(gè)參數(shù), 分別是代理目標(biāo)對(duì)象,以及我們要寫(xiě)入的屬性名稱(chēng)還有最后我們要寫(xiě)入的屬性值。我們可以做一些校驗(yàn),比如說(shuō)如果設(shè)置的是age,他的值就必須是整數(shù),否則就拋錯(cuò)。
{
????set(target,?property,?value)?{
????????console.log(target,?property,?value);
????????if?(property?===?'age')?{
????????????if?(!Number.isInteger(value))?{
????????????????throw?new?TypeError(``${value}?must?be?a?integer);
????????????}
????????}
????????target[property]?=?value;
????}
}
相比于Object.defineProperty, Proxy到底有哪些優(yōu)勢(shì)。
首先最明顯的優(yōu)勢(shì)就是在于Proxy要更為強(qiáng)大一些,那這個(gè)強(qiáng)大具體體現(xiàn)在Object.defineProperty只能監(jiān)聽(tīng)到對(duì)象屬性的讀取或者是寫(xiě)入,而Proxy除讀寫(xiě)外還可以監(jiān)聽(tīng)對(duì)象中屬性的刪除,對(duì)對(duì)象當(dāng)中方法的調(diào)用等等。
第二點(diǎn)優(yōu)勢(shì)就是對(duì)于數(shù)組對(duì)象進(jìn)行監(jiān)視,通常我們想要監(jiān)視數(shù)組的變化,基本要依靠重寫(xiě)數(shù)組方法,這也是Vue的實(shí)現(xiàn)方式,proxy可以直接監(jiān)視數(shù)組的變化。以往我們想要通過(guò)Object.defineProperty去監(jiān)視數(shù)組的操作最常見(jiàn)的方式是重寫(xiě)數(shù)組的操作方法,這也是Vue.js中所使用的方式,大體的方式就是通過(guò)自定義的方法去覆蓋掉數(shù)組原型對(duì)象上的push,shift之類(lèi)的方法,以此來(lái)劫持對(duì)應(yīng)的方法調(diào)用的過(guò)程。
對(duì)象的鍵支持什么類(lèi)型
這個(gè)問(wèn)題考察的是候選人的基礎(chǔ)知識(shí)是否扎實(shí)。
很多人都會(huì)認(rèn)為對(duì)象的鍵是字符串類(lèi)型,如果在以前確實(shí)沒(méi)錯(cuò),但是ES2015版本中對(duì)象的鍵類(lèi)型還可以是Symbol。
const?person?=?{
????name:?'yd',
????[Symbol()]:?18
}
這也是引出下面的Symbol。
Symbol
在ECMAScript2015之前,對(duì)象的屬性名都是字符串,而字符串是有可能會(huì)重復(fù)的。如果重復(fù)的話(huà)就會(huì)產(chǎn)生沖突。
以前解決這種問(wèn)題最好的方式就是約定,但是約定的方式只是規(guī)避了問(wèn)題并不是徹底解決了這個(gè)問(wèn)題。如果在這個(gè)過(guò)程中有人不遵守約定那這個(gè)問(wèn)題仍然會(huì)存在。
ES2015為了解決這個(gè)問(wèn)題提供了一種全新的原始數(shù)據(jù)類(lèi)型Symbol,翻譯過(guò)來(lái)的意思叫做符號(hào),翻譯過(guò)來(lái)就是表示一個(gè)獨(dú)一無(wú)二的值。通過(guò)Symbol函數(shù)就可以創(chuàng)建一個(gè)Symbol類(lèi)型的數(shù)據(jù),而且這種類(lèi)型的數(shù)據(jù)typeof的結(jié)果就是symbol,那這也就表示他確實(shí)是一個(gè)全新的類(lèi)型。
const?s?=?Symbol();
typeof?s;?//?symbol類(lèi)型
這種類(lèi)型最大的特點(diǎn)就是獨(dú)一無(wú)二,也就是說(shuō)我們通過(guò)Symbol函數(shù)創(chuàng)建的每一個(gè)值都是唯一的。他永遠(yuǎn)不會(huì)重復(fù)。
Symbol()?===?Symbol();?//?false
考慮到在開(kāi)發(fā)過(guò)程中的調(diào)試Symbol創(chuàng)建時(shí)允許接收一個(gè)字符串,作為這個(gè)值的描述文本, 對(duì)于我們多次使用Symbol時(shí)就可以區(qū)分出是哪一個(gè)Symbol,但這個(gè)參數(shù)也僅是描述作用,相同的描述字段生成的值仍是不同的。
const?s1?=?Symbol('foo');
const?s2?=?Symbol('foo');
s1?===?s2;?//?false
從ES2015開(kāi)始,對(duì)象就已經(jīng)允許使用Symbol作為屬性名。那也就是說(shuō)現(xiàn)在對(duì)象的屬性名可以是兩種類(lèi)型,字符串和Symbol。
const?person?=?{
????[Symbol()]:?123,
????[Symbol()]:?456
}
如果我們需要在全局去復(fù)用一個(gè)相同的Symbol值,我們可以使用全局變量的方式去實(shí)現(xiàn),或者是使用Symbol類(lèi)型提供的一個(gè)靜態(tài)方法去實(shí)現(xiàn)。具體就是Symbol的靜態(tài)方法for,這個(gè)方法接收一個(gè)字符串作為參數(shù),相同的參數(shù)一定對(duì)應(yīng)相同的值。
const?s1?=?Symbol.for('foo');
const?s2?=?Symbol.for('foo');
s1?===?s2;?//?true
這個(gè)方法維護(hù)了一個(gè)全局的注冊(cè)表,為字符串和Symbol提供了一個(gè)對(duì)應(yīng)關(guān)系。需要注意的是,在內(nèi)部維護(hù)的是字符串和Symbol的關(guān)系,那也就是說(shuō)如參數(shù)不是字符串,會(huì)轉(zhuǎn)換為字符串。
const?s1?=?Symbol.for('true');
const?s2?=?Symbol.for(true);
s1?===?s2;?//?true
JSONP
很多人對(duì)jsonp的理解都停留在概念上,沒(méi)有真正理解過(guò)他的原理,他為什么可以跨域,當(dāng)然不僅僅是script標(biāo)簽不受同源策略影響,實(shí)際上jsonp是一種前后端約定的解決方案。
不過(guò)現(xiàn)在基本已經(jīng)很少用到了。因?yàn)楝F(xiàn)在已經(jīng)有了更流行的CORS方案,相對(duì)來(lái)說(shuō)也會(huì)更安全,不過(guò)jsonp還是有其自身的優(yōu)勢(shì)的。
很多人都知道瀏覽器的同源策略,就是發(fā)送請(qǐng)求的頁(yè)面地址和被請(qǐng)求的接口地址的域名,協(xié)議,端口三者必須一致,否則瀏覽器就會(huì)攔截這種請(qǐng)求。瀏覽器攔截的意思不是說(shuō)請(qǐng)求發(fā)布出去,請(qǐng)求還是可以正常觸達(dá)服務(wù)器的,如果服務(wù)器正常返回了瀏覽器也會(huì)接收的到,只是不會(huì)交給我們所在的頁(yè)面。這一點(diǎn)查看network是可以看到的。
jsonp一般是利用script標(biāo)簽的src屬性,對(duì)于服務(wù)器來(lái)說(shuō)只有請(qǐng)求和響應(yīng)兩種操作,請(qǐng)求來(lái)了就會(huì)響應(yīng),無(wú)論響應(yīng)的是什么。請(qǐng)求的類(lèi)型實(shí)在太多了。
瀏覽器輸入一個(gè)url是一個(gè)請(qǐng)求,ajax調(diào)用一個(gè)接口也是一個(gè)請(qǐng)求,img和script的src也是請(qǐng)求。這些地址都會(huì)觸達(dá)服務(wù)器。那為什么jsonp一般會(huì)選用script標(biāo)簽?zāi)兀紫却蠹叶贾纒cript加載的js是沒(méi)有跨域限制的,因?yàn)榧虞d的是一個(gè)腳本,不是一個(gè)ajax請(qǐng)求。你可以理解為瀏覽器限制的是XMLHttpRequest這個(gè)對(duì)象,而script是不使用這個(gè)對(duì)象的。
僅僅沒(méi)有限制還不夠,還有一個(gè)更重要的點(diǎn)因?yàn)閟cript是執(zhí)行js腳本的標(biāo)簽,他所請(qǐng)求到的內(nèi)容會(huì)直接當(dāng)做js來(lái)執(zhí)行。
這也可以看出,jsonp和ajax對(duì)返回參數(shù)的要求是不同的,jsonp需要服務(wù)返回一段js腳本,ajax需要返回的是數(shù)據(jù)。
因此這就要求服務(wù)器單獨(dú)來(lái)處理jsonp這中請(qǐng)求,一般服務(wù)器接口會(huì)把響應(yīng)的數(shù)據(jù)通過(guò)函數(shù)調(diào)用的方式返回,比如說(shuō)返回的內(nèi)容是'yd',那就要返回成cb('yd')
cb('yd')
這是一段函數(shù)調(diào)用的腳本,通過(guò)script標(biāo)簽加載之后會(huì)立即執(zhí)行的,如果我們?cè)谌侄x一個(gè)cb函數(shù)。那么這段腳本執(zhí)行的時(shí)候就會(huì)調(diào)用到我們定義的那個(gè)函數(shù),函數(shù)中的參數(shù)就是服務(wù)返回的值了。前端也就可以在這個(gè)函數(shù)中獲取到了。
function?cb?(data)?{
????console.log(data);
}
所以說(shuō)jsonp是前后端共同約定的一種結(jié)果。
CORS
瀏覽器通過(guò)同源策略來(lái)限制前后端的跨域問(wèn)題,但同時(shí)也給了相應(yīng)的解決方案。服務(wù)器在返回相應(yīng)的時(shí)候可以通過(guò)設(shè)置響應(yīng)頭來(lái)允許哪些網(wǎng)址跨域請(qǐng)求,這樣前端就可以成功拿到響應(yīng)的結(jié)果了。所以這也證實(shí)了,前端拿不到結(jié)果不是服務(wù)器不返回,而是瀏覽器沒(méi)有給到前端。
Access-Control-Allow-Origin:?www.xxxx.com
webpack的proxy是如何解決跨域的?
前面說(shuō)了,跨域是因?yàn)闉g覽器的同源策略限制,問(wèn)題發(fā)生在瀏覽器身上,那我們是不是可以避過(guò)瀏覽器呢。前面我寫(xiě)過(guò)一篇前端需要知道的nginx,里面介紹了反向代理和負(fù)載均衡,其實(shí)這里就像是反向代理一樣。我們?cè)谑褂脀ebpack開(kāi)發(fā)項(xiàng)目的時(shí)候,webpack的dev-server模塊會(huì)啟動(dòng)一個(gè)服務(wù)器,這個(gè)服務(wù)器不止幫我們做了自動(dòng)更新,同時(shí)也可以做到反向代理。就是我們把請(qǐng)求發(fā)送給webpack-dev-server, 然后webpack-dev-server再去請(qǐng)求后端服務(wù)器,服務(wù)之間的請(qǐng)求是沒(méi)有跨域問(wèn)題的,只要后端返回了webpack-dev-server就能拿到,然后再返回給前端。好了基本上就問(wèn)了這幾個(gè)問(wèn)題,老板說(shuō)面試時(shí)間控制在20分鐘左右。
