App下載

2020前端面試都會(huì)問(wèn)啥?

猿友 2020-09-01 11:40:40 瀏覽數(shù) (2870)
反饋

文章轉(zhuǎn)載自公眾號(hào):前端工匠(微信號(hào):frontJS)

2020年注定是不平凡的一年,找工作的競(jìng)爭(zhēng)壓力可想而知,如何從眾多面試者中脫穎而出呢,總結(jié)了一波前端常見(jiàn)面試題,希望對(duì)大家有所幫助!

1. javascript 作用域與預(yù)解析

什么是預(yù)解析?

分兩步執(zhí)行:

第一步:(代碼還沒(méi)有執(zhí)行。預(yù)覽頁(yè)面之前,寫(xiě)完之后)

找程序中var關(guān)鍵字,如果找到了提前給var定義的變量賦值undefined

找程序中的普通函數(shù),如果找到了,函數(shù)提升,將整個(gè)函數(shù)賦值給函數(shù)名。

如果找的var的名字和函數(shù)名字相同,函數(shù)優(yōu)先。

第二步: 逐行解析代碼。按照上下順序。如果碰到函數(shù)定義,忽略。

重點(diǎn):函數(shù)內(nèi)部同樣適用于js預(yù)解析。

我們通過(guò)幾道面試題,來(lái)了解下作用域和和預(yù)解析的原理

function fun(){ console.log(n); var n = 456; console.log(n); } var n = 123; fun(n);

猜一猜此題中輸出的結(jié)果是?可能并不是你想的結(jié)果,why?

代碼分析如下:

1-5行定義函數(shù)fun

6行定義變量 n

7行執(zhí)行函數(shù)并傳入變量 n

注意:fun函數(shù)內(nèi)部有預(yù)解析。

預(yù)解析及執(zhí)行步驟:

  1. Fun函數(shù)開(kāi)始執(zhí)行前,將var n提前執(zhí)行,初始化為undefined

  1. 由于函數(shù)傳入?yún)?shù) n 并沒(méi)有使用,忽略。

  1. 開(kāi)始執(zhí)行第2行,輸出為undefined。

  1. 執(zhí)行第3行,此時(shí)即n = 456,即將n值重置為456。

  1. 執(zhí)行第4行,輸出改變后的n。

通過(guò)以上步驟分析,即可得知預(yù)解析的原理了(針對(duì)有var的變量提前賦初始值)

下面再看一題,看看函數(shù)預(yù)解析

函數(shù)預(yù)解析

猜一猜此題中輸出的結(jié)果是?可能并不是你想的結(jié)果,why?

代碼分析如下:

29行定義一個(gè)全局變量

30-32行定義一個(gè)函數(shù) f1

33-36行定義一個(gè)函數(shù) f2

37行執(zhí)行函數(shù) f2

38行輸出結(jié)果 n

預(yù)解析及執(zhí)行步驟:

1.代碼執(zhí)行前,預(yù)解析先初始化變量 n, f1, f2,將它們都置為 undefined.

2.接著執(zhí)行第29行,為變量n賦值

3.接著執(zhí)行第30-32行,為函數(shù)變量 f1 賦值,即 f1 為函數(shù)了

4.接著執(zhí)行第33-36行,為函數(shù)變量 f2 賦值

5.執(zhí)行第37行,即執(zhí)行 f2 函數(shù)。

  1. f2 函數(shù)執(zhí)行前,同樣預(yù)解析,先將 n 初始化為undefined,接著把 n 賦值為456,接著調(diào)用f1函數(shù)執(zhí)行。

  1. f1 在 f2 中執(zhí)行,那 f1 的作用域應(yīng)該是 f2 ,應(yīng)該輸出456?

8.35行執(zhí)行 f1 函數(shù)時(shí)無(wú)調(diào)用者,即 f1 函數(shù)為全局作用域,輸出全局 n 為 123

9.第38行直接輸出全局變量 n ,即123

繼續(xù)深入,再來(lái)一題:

預(yù)解析

猜一猜此題中輸出的結(jié)果是?可能并不是你想的結(jié)果,why?

代碼分析如下:

預(yù)解析只針對(duì)varfunction定義的變量

預(yù)解析及執(zhí)行步驟:

1.預(yù)解析先初始化變量length, obj, f1并賦值為undefined

2.接著為變量length賦值為 100

3.接著為函數(shù)變量 f1 賦值為函數(shù)

4.接著為變量`obj 賦值為對(duì)象

5.第52行,調(diào)用對(duì)象obj的 f2 函數(shù)執(zhí)行,傳入形參 f1 和1

6.第47行,f2 函數(shù)接收實(shí)參為 f1 , 接著執(zhí)行 f1 函數(shù)

7.同上,f1 函數(shù)執(zhí)行無(wú)調(diào)用者,作用域?yàn)槿郑?code>this指向window,輸出全局變量length,即100

8.第47行,f2 函數(shù)接收實(shí)參 f1 ,若要取到所有實(shí)參則需要arguments對(duì)象,第一個(gè)參數(shù)arguments[0]==f1,第二個(gè)arguments[1]==1,依此類(lèi)推。

9.第49行,arguments[0]()看上去是f1(),那也應(yīng)該輸出100?

10.注意arguments[0]作用域與f1的作用域并不相同,第48行直接執(zhí)行f1,無(wú)調(diào)用者,作用域?yàn)槿肿饔糜?,?code>arguments[0]作用域?yàn)?code>arguments對(duì)象,即thisarguments,則應(yīng)輸出 2,因?yàn)?code>arguments對(duì)象的屬性length為2。

2. 前端如何處理跨域

1、為什么會(huì)出現(xiàn)跨域問(wèn)題

同源策略(Sameoriginpolicy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會(huì)受到影響。可以說(shuō) Web 是構(gòu)建在同源策略基礎(chǔ)之上的,瀏覽器只是針對(duì)同源策略的一種實(shí)現(xiàn)。同源策略會(huì)阻止一個(gè)域的 javascript 腳本和另外一個(gè)域的內(nèi)容進(jìn)行交互。所謂同源(即指在同一個(gè)域)就是兩個(gè)頁(yè)面具有相同的協(xié)議(protocol),主機(jī)(host)和端口號(hào)(port)。

2、什么是跨域

當(dāng)一個(gè)請(qǐng)求url的協(xié)議、域名、端口三者之間任意一個(gè)與當(dāng)前頁(yè)面url不同即為跨域。

當(dāng)前頁(yè)面url 被請(qǐng)求頁(yè)面url 是否跨域 原因
http://m.hgci.cn/ http://m.hgci.cn/index.html 同源
http://m.hgci.cn/ http://m.hgci.cn/index.html 跨域 協(xié)議不同(http/https
http://m.hgci.cn http://www.baidu.cn/ 跨域 主域名不同(w3cschool/baidu
http://m.hgci.cn/ http://123.w3cschool.cn 跨域 子域名不同(www/123
www.test.com:8080/ www.test.com:7001 跨域 端口號(hào)不同

3、跨域解決方法

【1】設(shè)置document.domain解決無(wú)法讀取非同源網(wǎng)頁(yè)的 Cookie問(wèn)題

【2】跨文檔通信 API:window.postMessage()

【3】JSONP

【4】CORS

【5】Proxy

作為開(kāi)發(fā)人員,最關(guān)心的跨域一般是2種交互的跨域,即ProxyCORS,很多開(kāi)發(fā)只圖一時(shí)方便,使用了Proxy,在打包后就發(fā)現(xiàn)又有跨域了,不知道怎么解決,下面我們通過(guò)實(shí)例一點(diǎn)點(diǎn)給大家解析。

跨域出現(xiàn)

首先,需要重現(xiàn)跨域,先用node寫(xiě)一個(gè)簡(jiǎn)單的接口,如下

跨域出現(xiàn)

使用命令node啟動(dòng)這個(gè)服務(wù),則搭建了一個(gè)最簡(jiǎn)單的后端服務(wù)接口,然后使用前端ajax來(lái)請(qǐng)求這個(gè)接口,如下

前端ajax請(qǐng)求接口

創(chuàng)建一個(gè)簡(jiǎn)單的html頁(yè)面,再加上上面的簡(jiǎn)單ajax請(qǐng)求,在瀏覽器控制臺(tái)就看到了跨域error

跨域error

從日志上看出現(xiàn)了“Access-Control-Allow-Origin”,表示是訪問(wèn)源未被許可,即跨域了。

跨域解決之Proxy

現(xiàn)在項(xiàng)目一般都使用腳手架,即使用webpack,那可以使用webpack自帶的proxy特性來(lái)處理跨域,下面我們來(lái)配置一個(gè)簡(jiǎn)單的webpack項(xiàng)目,如下

1.創(chuàng)建配置文件webpack.config.js

創(chuàng)建配置文件

配置文件說(shuō)明項(xiàng)目入口文件在srcindex.js,打包輸出目錄為dist,使用proxy處理跨域,即前端所有請(qǐng)求會(huì)自動(dòng)跳轉(zhuǎn)到target指定的url

注意這里有一個(gè)前綴,若沒(méi)有可以不寫(xiě)。

2.創(chuàng)建src目錄及index.js

創(chuàng)建src目錄及index.js

3.創(chuàng)建工程依賴(lài)文件package.json

創(chuàng)建工程依賴(lài)文件

依賴(lài)文件中配置了webpack啟動(dòng)命令

Npm run dev 啟動(dòng)服務(wù)

Npm run start 啟動(dòng)服務(wù)

Npm run build 打包命令

當(dāng)啟動(dòng)服務(wù)后,打開(kāi)瀏覽器輸入 http://localhost:8080 ,即可看到一個(gè)空白頁(yè)面,打開(kāi)控制臺(tái)可以看到ajax請(qǐng)求

空白頁(yè)面

拿到交互的數(shù)據(jù)了。

這種方式是開(kāi)發(fā)最常用的,但是打包后就有問(wèn)題了,因?yàn)榇虬缶筒淮嬖?code>proxy了,跨域還是會(huì)存在,那應(yīng)該怎么解決?

跨域解決之CORS

這種方式是在后端配置,配置CORS后,前端無(wú)需任何處理即可訪問(wèn)后端的接口,無(wú)論是在開(kāi)發(fā)時(shí)還是部署時(shí)都是OK的。

下面,我們把proxy注釋掉,使用CORS方式處理,如下:

CORS方式處理

配置了cors后,接口就可以隨便訪問(wèn)了。

此時(shí),還需要把前端請(qǐng)求地址改一下,改為直接請(qǐng)求后端接口,如下

請(qǐng)求后端接口

刷新頁(yè)面,打開(kāi)控制臺(tái)可以看到請(qǐng)求地址為

請(qǐng)求地址

請(qǐng)求地址

通過(guò)此種方式,在開(kāi)發(fā)階段或部署都沒(méi)有問(wèn)題,這也是開(kāi)發(fā)中最常用的2種方式。

3. 什么是閉包?如何理解

閉包(closure)是javascript的一大難點(diǎn),也是它的特色。很多高級(jí)應(yīng)用都要依靠閉包來(lái)實(shí)現(xiàn)。

要理解閉包,首先要理解javascript的全局變量和局部變量。

javascript語(yǔ)言的特別之處就在于:函數(shù)內(nèi)部可以直接讀取全局變量,但是在函數(shù)外部無(wú)法讀取函數(shù)內(nèi)部的局部變量。

如何從外部讀取函數(shù)內(nèi)部的局部變量

如何從外部讀取函數(shù)內(nèi)部的局部變量?

我們有時(shí)候需要獲取到函數(shù)內(nèi)部的局部變量,正常情況下,這是辦不到的!只有通過(guò)變通的方法才能實(shí)現(xiàn)。那就是在函數(shù)內(nèi)部,再定義一個(gè)函數(shù)。

1、閉包的概念

上面代碼中的 f2 函數(shù),就是閉包。

各種專(zhuān)業(yè)文獻(xiàn)的閉包定義都非常抽象,我的理解是: 閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。

由于在javascript中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,所以說(shuō),閉包可以簡(jiǎn)單理解成“定義在一個(gè)函數(shù)內(nèi)部的函數(shù)“。

所以,在本質(zhì)上,閉包是將函數(shù)內(nèi)部和函數(shù)外部連接起來(lái)的橋梁。

2、閉包的用途

閉包可以用在許多地方。它的最大用處有兩個(gè),一個(gè)是前面提到的可以讀取函數(shù)內(nèi)部的變量,另一個(gè)就是讓這些變量的值始終保持在內(nèi)存中,不會(huì)在 f1 調(diào)用后被自動(dòng)清除。

為什么會(huì)這樣呢?原因就在于 f1 是 f2 的父函數(shù),而 f2 被賦給了一個(gè)全局變量,這導(dǎo)致 f2 始終在內(nèi)存中,而 f2 的存在依賴(lài)于 f1 ,因此 f1 也始終在內(nèi)存中,不會(huì)在調(diào)用結(jié)束后,被垃圾回收機(jī)制(garbage collection)回收。

在我們平時(shí)的代碼中經(jīng)常會(huì)用到閉包,比如在構(gòu)造函數(shù)中

構(gòu)造函數(shù)

//另一種寫(xiě)法

另一種寫(xiě)法

3、常見(jiàn)閉包的寫(xiě)法

常見(jiàn)閉包的寫(xiě)法

另一種調(diào)用方法

另一種調(diào)用方法

//定義函數(shù)并立即調(diào)用

定義函數(shù)并立即調(diào)用

4、閉包的實(shí)際應(yīng)用

使用閉包,我們可以做很多事情。比如模擬面向?qū)ο蟮拇a風(fēng)格;更優(yōu)雅,更簡(jiǎn)潔的表達(dá)出代碼;在某些方面提升代碼的執(zhí)行效率。

封裝

封裝

通過(guò)person.name是無(wú)法獲取到name的值,如果要獲取到name的值可以通過(guò)

Console.log(person.getName()); //直接獲取到 張三 person.setName("李四"); //重新設(shè)置新的名字 print(person.getName()); //獲取 李四

繼承

繼承

總結(jié):閉包就是一個(gè)函數(shù)引用另外一個(gè)函數(shù)的變量,因?yàn)樽兞勘灰弥圆粫?huì)被回收,因此可以用來(lái)封裝一個(gè)私有變量。這是優(yōu)點(diǎn)也是缺點(diǎn),不必要的閉包只會(huì)徒增內(nèi)存消耗!

以上就是W3Cschool編程獅關(guān)于2020前端面試都會(huì)問(wèn)啥?的相關(guān)介紹了,希望對(duì)大家有所幫助。

0 人點(diǎn)贊