2019前端面試題

1.什麼是面向對象?什麼是面向過程?javascript

1)面向對象的重點是對象。當解決一個問題的時候,面向對象會把事物抽象成對象,也就是說這個問題包含哪些對象,而後給這些對象賦一些屬性和方法,讓每一個對象執行本身的方法,問題獲得解決。css

2)面向過程的重點是過程。解決一個問題的時候,面向過程會把問題拆分紅一個個的函數和數據(方法的參數)。而後按照必定的順序執行這些方法,執行完這些方法,問題獲得解決。html

 

2.什麼是面向對象程序設計?前端

答:將計算機須要處理的問題都抽象成對象,在抽象成類,幫助人們實現對現實世界的抽象與數字建模。vue

面向對象的程序設計更加符合人的思考邏輯和對事物的處理。html5

 

3.什麼是對象?什麼是類?java

答:對象是由類實例化出來的,類的實例稱爲對象。程序員

類是具備相同特徵和功能的對象的抽象。es6

類和對象的關係就比如模具和鑄件的關係,類的實例化結果就是對象,而對象的抽象就是類。web

 

4.什麼是繼承?

在面向對象的編程中,當兩個類具備相同的特徵(屬性)和行爲(方法)時,能夠將相同的部分抽取出來放到一個類中做爲父類,其餘兩個類繼承這個父類。繼承後的子類自動擁有了父類的部分屬性和方法。

經過繼承建立的新類被稱爲「子類」或「派生類」

被繼承的類稱爲「基類」、「父類」或「超類」

好比:

狗{吠;}牧羊犬 繼承 狗{放羊;}上面的例子中,狗類是父類,牧羊犬類是子類。牧羊犬類經過繼承得到狗類的吠的能力,同時增長了本身獨有的放羊的能力。

 

JS中的繼承主要是經過原型鏈實現的

每一個構造函數(constructor)都有一個原型對象(prototype),原型對象都包含一個指向構造函數的指針,而實例(instance)都包含一個指向原型對象的內部指針

若是試圖引用對象(實例instance)的某個屬性,會首先在對象內部尋找該屬性,直至找不到,而後纔在該對象的原型(instance.prototype)裏去找這個屬性

http://www.javashuo.com/article/p-zugxclij-h.html

 

5.談談你對前端性能優化的理解

1)請求數量,合併腳本和樣式表,拆分初始化負載

2)請求帶寬,精簡JavaScript,移除重複腳本,圖像優化,將icon作成字體

3)頁面結構:將樣式表放在頂部,將腳本放在底部,儘早刷新文檔的輸出

 

6.爲何使用框架?使用框架的優點?

1)重複應用的外部JS:使用框架後咱們能夠把這些文件寫在入口文件中,一勞永逸

2)組件化:組件是前端框架裏很是強大的功能之一,它能夠擴展你的HTML,封裝能夠重用的代碼塊,好比你的輪播圖、tab切換、頁面頭部、頁面底部等等。

3)開發週期長:jQuery開發時,須要頻繁的操做DOM,幾乎任何動態效果都須要去選擇DOM來進行相應的操做,這使開發變得麻煩起來,不少的時間都用到了操做DOM上,項目的開發週期天然被延長。

使用框架開發,框架中封裝許多的頻繁使用的功能,例如Angular中的指令,指令功能有數據綁定,表單驗證,數據格式化等等。這時前端的重點只須要放在數據邏輯部分,而不須要花費很大的精力去操做DOM完成功能,從而加快項目進度。

4)性能:不少DOM操做會引發迴流和重繪,對於jQuery來講,大量的操做DOM雖然方便,可是很浪費頁面性能。

框架和jQuery雖然都會操做DOM,可是框架把大量的DOM進行了處理和優化(例如Vue的虛擬DOM),經過數據驅動,就能渲染出DOM,大大提高了性能。

 

7.盒模型包含什麼?

答:padding 、 margin 、 content 、 border

 

8.談談cookie的弊端?

1)每一個特定域名下生成的cookie數量有限

2)cookie的最大大約爲4096字節,爲了兼容性,通常不能超過4095字節

3)安全性問題。若是cookie被人攔截了,就能夠取得全部的session信息

 

9.瀏覽器本地存儲?

答:在HTML5中提供了sessionStorage和localStorage。

sessionStorage用於本地存儲一個會話(session)中的數據,這些數據只有在同一個會話中的頁面才能訪問而且當會話結束後數據也隨之銷燬,是會話級別的存儲。

localStorage用於持久化的本地存儲,除非主動刪除數據,不然數據是永遠不會過時的。

 

10.web storage和cookie的區別

a. Cookie的大小是受限的

b. 每次你請求一個新的頁面的時候Cookie都會被髮送過去,這樣無形中浪費了帶寬

c. cookie還須要指定做用域,不能夠跨域調用

d. Web Storage擁有setItem,getItem等方法,cookie須要前端開發者本身封裝setCookie,getCookie

e. Cookie的做用是與服務器進行交互,做爲HTTP規範的一部分而存在 ,而Web Storage僅僅是爲了在本地「存儲」數據而生

f. IE七、IE6中的UserData經過簡單的代碼封裝能夠統一到全部的瀏覽器都支持web storage

 

11.線程與進程的區別

根本區別:進程是操做系統資源分配的基本單位,而線程是任務調度和執行的基本單位

http://www.javashuo.com/article/p-wwzriyfh-gp.html

 

12.什麼叫優雅降級和漸進加強?

漸進加強 progressive enhancement:

針對低版本瀏覽器進行構建頁面,保證最基本的功能,而後再針對高級瀏覽器進行效果、交互等改進和追加功能達到更好的用戶體驗。

優雅降級 graceful degradation:

一開始就構建完整的功能,而後再針對低版本瀏覽器進行兼容。

區別:

a. 優雅降級是從複雜的現狀開始,並試圖減小用戶體驗的供給

b. 漸進加強則是從一個很是基礎的,可以起做用的版本開始,並不斷擴充,以適應將來環境的須要

c. 降級(功能衰減)意味着往回看;而漸進加強則意味着朝前看,同時保證其根基處於安全地帶

 

13.web socket

要作長鏈接的話,是不能用http協議來作的,由於http協議已是應用層協議了,而且http協議是無狀態的,而咱們要作長鏈接,確定是須要在應用層封裝本身的業務,因此就須要基於TCP協議來作,而基於TCP協議的話,就要用到Socket了

  • Socket是java針對tcp層通訊封裝的一套網絡方案
  • TCP協議咱們知道,是基於ip(或者域名)和端口對指定機器進行的點對點訪問,他的鏈接成功有兩個條件,就是對方ip能夠到達和端口是開放的
  • Socket能完成TCP三次握手,而應用層的頭部信息須要本身去解析,也就是說,本身要制定好協議,而且要去解析byte

14.HTTP 與 TCP/IP 的區別?

TCP是傳輸層協議,定義數據傳輸和鏈接方式的規範。握手過程當中傳送的包裏不包含數據,三次握手完畢後,客戶端與服務器才正式開始傳送數據。

HTTP 超文本傳送協議(Hypertext Transfer Protocol )是應用層協議,定義的是傳輸數據的內容的規範。

HTTP協議中的數據是利用TCP協議傳輸的,特色是客戶端發送的每次請求都須要服務器回送響應,它是TCP協議族中的一種,默認使用 TCP 80端口。

比如網絡是路,TCP是跑在路上的車,HTTP是車上的人。每一個網站內容不同,就像車上的每一個人有不一樣的故事同樣。

關於TCP/IP和HTTP協議的關係,網絡有一段比較容易理解的介紹:「咱們在傳輸數據時,能夠只使用(傳輸層)TCP/IP協議,可是那樣的話,若是沒有應用層,便沒法識別數據內容,若是想要使傳輸的數據有意義,則必須使用到應用層協議,應用層協議有不少,好比HTTP、FTP、TELNET等,也能夠本身定義應用層協議。WEB使用HTTP協議做應用層協議,以封裝HTTP 文本信息,而後使用TCP/IP作傳輸層協議將它發到網絡上。」

http://www.javashuo.com/article/p-qvsvllmo-gp.html

 

15.爲何說HTTP鏈接是無狀態的?

答:客戶端和服務器在某次會話產生的數據,這些數據不會被保留。

 

16.什麼是websocket?

WebSocket 是 HTML5 開始提供的一種在單個 TCP 鏈接上進行全雙工通信的協議。

WebSocket 使得客戶端和服務器之間的數據交換變得更加簡單,容許服務端主動向客戶端推送數據。在 WebSocket API 中,瀏覽器和服務器只須要完成一次握手,二者之間就直接能夠建立持久性的鏈接,並進行雙向數據傳輸。

在 WebSocket API 中,瀏覽器和服務器只須要作一個握手的動做,而後,瀏覽器和服務器之間就造成了一條快速通道。二者之間就直接能夠數據互相傳送。

http://www.javashuo.com/article/p-uokgcivn-go.html

 

17.網絡七層協議(OSI)是哪些?

答:1.物理層   2.數據鏈路層  3.網絡層  4.傳輸層  5.會話層  6.表示層  7.應用層

 

18.什麼是同源策略?

答:同源策略指的是協議、域名、端口相同,是一種安全協議

指一段腳本只能讀取來自同一窗口的文檔和屬性

 

19.AMD、CMD、CommonJS 和 ES6 的對比

https://blog.csdn.net/tangxiujiang/article/details/81104174

 

20.瀏覽器的內核分別是什麼?

IE瀏覽器的內核Trident;

Mozilla的Gecko;

Chrome的Blink(WebKit的分支);

Opera內核原爲Presto,現爲Blink;

 

21.前端頁面有哪三層構成,分別是什麼?做用是什麼?

a. 結構層:由 HTML 或 XHTML 之類的標記語言負責建立,僅負責語義的表達。解決了頁面「內容是什麼」的問題。

b. 表示層:由CSS負責建立,解決了頁面「如何顯示內容」的問題。

c. 行爲層:由腳本負責。解決了頁面上「內容應該如何對事件做出反應」的問題。

 

23.談談vue中的MVVM模式?

答:MVVM全稱是Model-View-ViewModel

Vue是以數據爲驅動的,Vue自身將DOM和數據進行綁定,一旦建立綁定,DOM和數據將保持同步,每當數據發生變化,DOM會跟着變化。

ViewModel是Vue的核心,它是Vue的一個實例。Vue實例時做用域的這個HTML元素能夠是body,也能夠是某個id所指代的元素。

DOMListenersDataBindings是實現雙向綁定的關鍵。

DOMListeners監聽頁面全部View層DOM元素的變化,當發生變化,Model層的數據隨之變化;

DataBindings監聽Model層的數據,當數據發生變化,View層的DOM元素隨之變化。

MVVM框架提倡把渲染和邏輯分離。簡單來講就是不要再讓 JS 直接操控 DOMJS 只須要管理狀態便可,而後再經過一種模板語法來描述狀態和界面結構的關係。

 

24.v-showv-if指令的共同點和不一樣點?

  • v-show指令是經過修改元素的displayCSS屬性讓其顯示或者隱藏
  • v-if指令是直接銷燬和重建DOM達到讓元素顯示和隱藏的效果

25.keep-alive

keep-alive是Vue提供的一個抽象組件,用來對組件進行緩存,從而節省性能,因爲是一個抽象組件,因此在vue頁面渲染完畢後不會被渲染成一個DOM元素

https://www.jianshu.com/p/4b55d312d297

 

26.Vue生命週期

1)beforeCreate:

完成實例初始化,初始化非響應式變量;

this指向建立的實例;

能夠加載loading事件;

data computed watch methods 上的方法和數據均不能訪問;

2)created:

實例建立完成;

完成數據(data props computed)的初始化,導入依賴項;

可訪問data computed watch methods上的數據和方法;

未掛載DOM,不能訪問$el,$ref爲空;

可在這結束loading,還能作一些初始化,實現函數自執行;

能夠對data數據進行操做,可進行一些請求,請求不易過多,避免白屏時間太長;

若在此階段進行的 DOM 操做必定要放在 Vue.nextTick() 的回調函數中

3)beforeMount:

有了el,編譯了template/outerHTML;

能找到對應的template,並編譯成render函數;

4)mounted:

完成建立vm.$el,和雙向綁定;

完成掛載DOM 和渲染;可在mounted鉤子對掛載的dom進行操做;

即有了DOM 且完成了雙向綁定,可訪問DOM節點,$ref;

可在這發起後端請求,拿回數據,配合路由鉤子作一些事情;

可對DOM 進行操做;

5)beforeUpdate:

數據更新以前;

可在更新前訪問現有的DOM,如手動移除添加的事件監聽器;

6)updated:

完成虛擬DOM的從新渲染和打補丁;

組件DOM 已完成更新;

可執行依賴的dom 操做;

注意:不要在此函數中操做數據,會陷入死循環的。

7)activated:

在使用vue-router時有時須要使用<keep-alive></keep-alive>來緩存組件狀態,這個時候created鉤子就不會被重複調用了
若是咱們的子組件須要在每次加載的時候進行某些操做,可使用activated鉤子觸發

8)deactivated:

keep-alive 組件被移除時使用

9)beforeDestory:

在執行app.$destroy()以前

可作一些刪除提示,如:你確認刪除XX嗎? 

可用於銷燬定時器,解綁全局時間 銷燬插件對象

10)destroyed:

當前組件已被刪除,銷燬監聽事件 組件 事件 子實例也被銷燬

這時組件已經沒有了,你沒法操做裏面的任何東西了

http://www.javashuo.com/article/p-mzpconrz-ge.html

 

27.父子組件的生命週期?

僅當子組件完成掛載後,父組件纔會掛載

當子組件完成掛載後,父組件會主動執行一次beforeUpdate/updated鉤子函數(僅首次)

父子組件在data變化中是分別監控的,可是在更新props中的數據是關聯的(可實踐)

銷燬父組件時,先將子組件銷燬後纔會銷燬父組件

 

兄弟組件的初始化(mounted以前)分開進行,掛載是從上到下依次進行

當沒有數據關聯時,兄弟組件之間的更新和銷燬是互不關聯的

 

28.什麼是Vue的生命週期?

Vue實例從建立到銷燬的過程,就是生命週期。

 

29.Vue生命週期的做用是什麼?

Vue生命週期有不少事件鉤子,讓咱們在控制整個Vue實例的過程更容易造成好的邏輯。

 

30.Vue生命週期總共有幾個階段?
答:它能夠總共分爲8個階段:建立前/後, 載入前/後,更新前/後,銷燬前/銷燬後。

 

31.Vue雙向綁定的原理是什麼?

Vue採用的是數據劫持結合發佈和-訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調

http://www.javashuo.com/article/p-pvlyorwx-hu.html

 

32.Vue組件之間的參數傳遞?

1.父組件與子組件傳值

父組件傳給子組件:子組件經過props方法接受數據;

子組件傳給父組件:$emit方法傳遞參數

2.非父子組件間的數據傳遞,兄弟組件傳值

eventBus,就是建立一個事件中心,至關於中轉站,能夠用它來傳遞事件和接收事件。項目比較小時,用這個比較合適。

(雖然也有很多人推薦直接用VUEX,具體來講看需求咯。技術只是手段,目的達到纔是王道。)

 

33.Vuex中有5中默認的基礎對象

  • state:存儲狀態(變量)
  • getters:對數據獲取以前的再次編譯,能夠理解爲state的計算屬性。咱們在組件中使用 $sotre.getters.fun()
  • mutations:修改狀態,而且是同步的。在組件中使用$store.commit('',params)。這個和咱們組件中的自定義事件相似。
  • actions:異步操做。在組件中使用是$store.dispath('')
  • modules:store的子模塊,爲了開發大型項目,方便狀態管理而使用的。這裏咱們就不解釋了,用起來和上面的同樣。

 

34.Vuex是什麼?

答:vuex 是一個專門爲vue.js應用程序開發的狀態管理模式。

這個狀態咱們能夠理解爲在data中的屬性,須要共享給其餘組件使用的部分。

也就是說,是咱們須要共享的data,使用vuex進行統一集中式的管理。

 

35.Vuex使用

http://www.javashuo.com/article/p-fdwnabwi-go.html

 

36.Vuex中mutation和action的區別

答:mutation 有必須同步執行這個限制,Action 就不受約束!咱們能夠在 action 內部執行異步操做

http://www.javashuo.com/article/p-enotvqwo-gn.html

 

37.原型、原型鏈、constructor

每一個函數都有一個prototype屬性,prototype是函數的原型對象。原型對象是用來給實例共享屬性和方法的

Javascript中全部的對象都是Object的實例,並繼承Object.prototype的屬性和方法,也就是說,Object.prototype是全部對象的爸爸

每一個對象都有__proto__屬性,這個__proto__指向的是建立這個對象的構造函數的prototype

 

Javascript語言的繼承機制一直很難被人理解

它沒有"子類"和"父類"的概念,也沒有"類"(class)和"實例"(instance)的區分,全靠一種很奇特的"原型鏈"(prototype chain)模式,來實現繼承

 

每一個對象都有一個constructor屬性,它引用了初始化該對象的構造函數

 

http://www.javashuo.com/article/p-xnxtvxpv-gn.html

http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html

 

38.JS的基本數據類型和引用數據類型以及深拷貝和淺拷貝

基本數據類型:

他們的值在內存中佔據着固定大小的空間,並被保存在內存中;

當一個變量向另外一個變量複製基本類型的值,會建立這個值的副本,而且咱們不能給基本數據類型的值添加屬性;

Undefined / Null / Boolean / Number / String,它們是直接按值存放的,能夠直接訪問。

引用數據類型:(對象、函數、數組

複雜的數據類型便是引用類型,它的值是對象,保存在內存中,包含引用類型值的變量實際上包含的不是對象自己,而是一個指向該對象的指針

從一個變量向另外一個變量複製引用類型的值,複製的實際上是指針地址而已,所以兩個變量最終都指向同一個對象。

訪問引用數據類型的值時,首先從棧中得到該對象的地址指針,而後再從堆內存中取得所需的數據。

 

淺拷貝:是拷貝一層,深層次的對象級別的就拷貝引用;

深拷貝:是拷貝多層,每一級別的數據都會拷貝出來;

 

淺拷貝的時候若是數據是基本數據類型,那麼就如同直接賦值那種,會拷貝其自己,若是除了基本數據類型以外還有一層對象,那麼對於淺拷貝而言就只能拷貝其引用,對象的改變會反應到拷貝對象上;

可是深拷貝就會拷貝多層,即便是嵌套了對象,也會都拷貝出來。

 

當咱們使用對象拷貝時,若是屬性是對象或數組時,這時咱們傳遞的只是一個地址。所以子對象在訪問該屬性時,會根據地址回溯到父對象指向的堆內存中,即父子對象發生了關聯,二者的屬性值會指向同一內存空間。

 

看一個比較經典的面試題:

var a = function() {console.log(11)};
 
var b = function() {console.log(11)};
 
console.log( a==b ); //false
 
 
console.log( {}=={} ); //false
 
console.log( []==[] ); //false

爲何結果都是false?

變量 a 實際保存的是指向堆內存中對象的一個指針,而 b 保存的是指向堆內存中另外一個對象的一個指針;

雖然這兩個對象的值是同樣的,但它們是獨立的2個對象,佔了2分內存空間;因此 a == b 爲 false

 

var a = {}; 

var b = a;
console.log( a
== b ); // true

這時變量 b 複製了變量 a 保存的指針,它們都指向堆內存中同一個對象;因此 a == b 爲 true

 

傳值與傳址:

基本類型與引用類型最大的區別實際就是 傳值 與 傳址 的區別

var a = [1,2,3,4,5];
 
var b = a;
 
var c = a[0];
 
console.log(b); // [1,2,3,4,5]
 
console.log(c); // 1
 
 
b[4] = 6;
 
c = 7;
 
console.log(a[4]); //6
 
console.log(a[0]); //1

從上面代碼能夠得知,當改變b中的數據時,a也發生了變化;可是當咱們改變c的數值時,a卻沒有發生改變

這就是傳值與傳址的區別。由於a是數組,屬於引用類型,因此a給b傳的是棧中的地址,而不是堆內存中的對象。

而c僅僅是從a堆內存中獲取的一個數值,並保存在棧中。因此b修改的時候,會根據地址回到a堆內存中修改;c則直接在棧中修改,而且不能指向a堆內存中。

 

https://blog.csdn.net/Bruce__taotao/article/details/82690506

https://www.cnblogs.com/c2016c/articles/9328725.html

https://blog.csdn.net/weixin_37719279/article/details/81240658

 

39.什麼是遞歸?

https://pushy.site/2018/02/20/recursion/

 

40.什麼是閉包?閉包有什麼做用?使用閉包的好處是什麼?

 

41.什麼是變量做用域?

變量的做用域就兩種:全局變量和局部變量

全局做用域: 
最外層函數定義的變量擁有全局做用域,即對任何內部函數來講,都是能夠訪問的

局部做用域: 
和全局做用域相反,局部做用域通常只在固定的代碼片斷內可訪問到,而對於函數外部是沒法訪問的,最多見的例如函數內部

<script>
      function fn(){ var innerVar = "inner"; } fn(); console.log(innerVar);// ReferenceError: innerVar is not defined
</script>

須要注意的是,函數內部聲明變量的時候,必定要使用var命令。若是不用的話,你實際上聲明瞭一個全局變量!

  <script>
      function fn(){ innerVar = "inner"; } fn(); console.log(innerVar);// result:inner
   </script>

 

再來看一個代碼:

 <script>
      var scope = "global"; function fn(){ console.log(scope);//result:undefined
         var scope = "local"; console.log(scope);//result:local;
 } fn(); </script>

頗有趣吧,第一個輸出竟然是undefined,本來覺得它會訪問外部的全局變量(scope=」global」),可是並無。

這能夠算是javascript的一個特色,只要函數內定義了一個局部變量,函數在解析的時候都會將這個變量「提早聲明」:

 <script>
      var scope = "global"; function fn(){ var scope;//提早聲明瞭局部變量
         console.log(scope);//result:undefined
         scope = "local"; console.log(scope);//result:local;
 } fn(); </script>

然而,也不能所以草率地將局部做用域定義爲:用var聲明的變量做用範圍起止於花括號之間。
javascript並無塊級做用域
那什麼是塊級做用域?
像在C/C++中,花括號內中的每一段代碼都具備各自的做用域,並且變量在聲明它們的代碼段以外是不可見的,好比下面的c語言代碼:

for(int i = 0; i < 10; i++){ //i的做用範圍只在這個for循環
} printf("%d",&i);//error

可是javascript不一樣,並無所謂的塊級做用域,javascript的做用域是相對函數而言的,能夠稱爲函數做用域

<script>
      for(var i = 1; i < 10; i++){ //coding
 } console.log(i); //10 
</script>

 

42.什麼是做用域鏈?什麼是執行環境?

個人理解就是,根據在內部函數能夠訪問外部函數變量的這種機制,用鏈式查找決定哪些數據能被內部函數訪問。 

想要知道js怎麼鏈式查找,就得先了解js的執行環境

每一個函數運行時都會產生一個執行環境,而這個執行環境怎麼表示呢?js爲每個執行環境關聯了一個變量對象。環境中定義的全部變量和函數都保存在這個對象中。

全局執行環境是最外圍的執行環境,全局執行環境被認爲是window對象,所以全部的全局變量和函數都做爲window對象的屬性和方法建立的。

js的執行順序是根據函數的調用來決定的,當一個函數被調用時,該函數環境的變量對象就被壓入一個環境棧中。而在函數執行以後,棧將該函數的變量對象彈出,把控制權交給以前的執行環境變量對象。 
舉個例子:

 

  <script>
      var scope = "global"; 
      function fn1(){
         return scope; 
      }
      function fn2(){
         return scope;
      }
      fn1();
      fn2();
   </script>

 

上面代碼執行狀況演示: 
執行環境

 

http://www.javashuo.com/article/p-expedgrq-ku.html

 

43.Vue組件

https://www.jianshu.com/p/7e825cd5f086

 

44.優化圖片加載的方法有哪些?

a. 圖片懶加載,滾動到相應位置才加載圖片。

b. 圖片預加載,若是爲幻燈片、相冊等,將當前展現圖片的前一張和後一張優先下載。

c. 使用CSSsprite,SVGsprite,Iconfont、Base64等技術,若是圖片爲css圖片的話。

d. 若是圖片過大,可使用特殊編碼的圖片,加載時會先加載一張壓縮的特別厲害的縮略圖,以提升用戶體驗。

 

45.什麼是token驗證?

Token是在客戶端頻繁向服務端請求數據,服務端頻繁的去數據庫查詢用戶名和密碼並進行對比,判斷用戶名和密碼正確與否,並做出相應提示,在這樣的背景下,Token便應運而生。

Token是服務端生成的一串字符串,以做客戶端進行請求的一個令牌,當第一次登陸後,服務器生成一個Token便將此Token返回給客戶端,之後客戶端只需帶上這個Token前來請求數據即

可,無需再次帶上用戶名和密碼。

 

46.使用基於 Token 的身份驗證方法,在服務端不須要存儲用戶的登陸記錄。大概的流程是這樣的:

1.客戶端使用用戶名跟密碼請求登陸

2.服務端收到請求,去驗證用戶名與密碼

3.驗證成功後,服務端會簽發一個 Token,再把這個 Token 發送給客戶端

4.客戶端收到 Token 之後能夠把它存儲起來,好比放在 Cookie 裏或者 Local Storage 裏

5.客戶端每次向服務端請求資源的時候須要帶着服務端簽發的 Token

6.服務端收到請求,而後去驗證客戶端請求裏面帶着的 Token,若是驗證成功,就向客戶端返回請求的數據

 

47.堆、棧

棧(stack):先進後出;自動分配內存空間,由系統自動釋放;使用的是一級緩存,他們一般都是被調用時處於存儲空間中,調用完當即釋放。

堆(heap):隊列優先,先進先出;動態分配內存,大小不定也不會自動釋放;存放在二級緩存中,生命週期由虛擬機的垃圾回收算法來決定;通常由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收。

 

48.js中 == 和 === 有什麼區別?

== 用於通常比較,=== 用於嚴格比較,== 在比較的時候能夠轉換數據類型,=== 嚴格比較,只要類型不匹配就返回 flase 

 

49.JS語言特色

JS做爲腳本語言,它的主要用途是與用戶互動,以及操做DOM。這決定了它只能是單線程,不然會帶來很複雜的同步問題,也就是同一時刻只能作一件事情。全部任務只能在一個線程上完成,一次只能作一件事。前面的任務沒作完,後面的任務只能等着。

可是隨着業務的不斷增長,只是單純的單線程模式已經可能沒法知足咱們的需求了。因而在html5中新增了後臺任務worker API。

瀏覽器的線程,瀏覽器中主要的線程包括,UI渲染線程,JS主線程,GUI事件觸發線程,http請求線程

 

看一個經典的面試題:

  function a() {
        setTimeout(function () {
            alert(1)
        }, 0);
        alert(2);
    }

    a();

代碼中的 setTimeout 設爲 0,也就是延遲 0ms,看上去是不作任何延遲馬上執行,即依次彈出 「1」、「2」。但實際的執行結果確是 「2」、「1」。其中的緣由得從 setTimeout 的原理提及:

JavaScript 是單線程執行的,也就是沒法同時執行多段代碼,當某一段代碼正在執行的時候,全部後續的任務都必須等待,造成一個隊列,一旦當前任務執行完畢,再從隊列中取出下一個任務。這也常被稱爲 「阻塞式執行」。

因此一次鼠標點擊,或是計時器到達時間點,或是 Ajax 請求完成觸發了回調函數,這些事件處理程序或回調函數都不會當即運行,而是當即排隊,一旦線程有空閒就執行。

假如當前 JavaScript 進程正在執行一段很耗時的代碼,此時發生了一次鼠標點擊,那麼事件處理程序就被阻塞,用戶也沒法當即看到反饋,事件處理程序會被放入任務隊列,直到前面的代碼結束之後纔會開始執行。

setTimeout(fn, 0)的含義是,指定某個任務在主線程最先可得的空閒時間執行,也就是說,當前代碼執行完(執行棧清空)之後,儘量的早執行。它在「任務隊列」的尾部添加一個事件,所以要等到同步任務和「任務隊列」現有的事件都處理完,纔會獲得執行。

HTML5標準規定了setTimeout()的第二個參數的最小值不得小於4毫秒,若是低於這個值,則默認是4毫秒。在此以前。老版本的瀏覽器都將最短期設爲10毫秒。另外,對於那些DOM的變更(尤爲是涉及頁面從新渲染的部分),一般是間隔16毫秒執行。這時使用requestAnimationFrame()的效果要好於setTimeout();

注意:setTimeout()只是將事件插入了「任務隊列」,必須等當前代碼(執行棧)執行完,主線程纔會去執行它指定的回調函數。要是當前代碼消耗時間很長,也有可能要等好久,因此並沒辦法保證回調函數必定會在setTimeout()指定的時間執行。因此,setTimeout()的第二個參數表示的是最少時間,並不是是確切時間。

settimeout(0)就起到了一個將事件加入到隊列中,待執行的一個功能效果!

定時器佔用cpu較多,建議酌情使用。

 

50.如何實現js的多線程?

JS爲咱們提供了一個Worker類,它的做用就是爲了解決這種阻塞的現象。當咱們使用這個類的時候,它就會向瀏覽器申請一個新的線程這個線程就用來單獨執行一個js文件

Web Worker 是運行在後臺的 JavaScript,獨立於其餘腳本,不會影響頁面的性能。您能夠繼續作任何願意作的事情:點擊、選取內容等等,而此時 Web Worker 在後臺運行。

Worker就是爲了JavaScript 創造多線程環境,容許主線程建立 Worker 線程,將一些任務分配給後者運行。

開啓後臺線程,在不影響前臺線程的前提下作一些耗時或者異步的操做。

由於是不一樣的線程,因此主線程與worker線程互不干擾。也不會相互打斷。因此在一些場景能夠提升頁面的流程性。Worker 線程一旦新建成功,就會始終運行,不會被主線程上的活動(好比用戶點擊按鈕、提交表單)打斷。這樣有利於隨時響應主線程的通訊。

可是,這也形成了 Worker 比較耗費資源,不該該過分使用,並且一旦使用完畢,就應該關閉。

var worker = new Worker(js文件路徑);  // 這個語句就會申請一個線程用來執行這個js文件

固然,在主線程中有一些方法來實現對新線程的控制和數據的接收。在這裏,咱們只說比較經常使用的幾個方法。

//postMessage(msg);
//postMessage方法把在新線程執行的結果發送到瀏覽器的js引擎線程裏
worker.onmessage = function(){
    //獲取在新線程中執行的js文件發送的數據 用event.data接收數據
    console.log( event.data )
};
setTimeout( function(){
    worker.terminate();
    //terminate方法用於關閉worker線程
},2000)
    
setTimeout( function(){
    worker = new Worker("js/test22.js");
    //再次開啓worker線程
},3000)

 

使用規則:

  1. 必須同源:也就是說js文件的路徑必須和主線程的腳本同源。防止了外部引用。
  2. dom限制:在worker線程中不能操做dom(document,window,parent)。注意可使用瀏覽器的navigator和location對象。
  3. 通信限制:worker線程和主線程不在一個上下文中因此不能直接通信。也就是說主線程定義的變量在worker中也是不能使用的。全部只能經過消息完成。
  4. 提示禁止:worker線程不能alert和confirm,這個不知到具體緣由?
  5. 傳值dom:進行消息通信也不能傳值dom只能是變量。
  6. ie限制:ie9不能使用!ie9不能使用!ie9不能使用!

https://www.cnblogs.com/yanbigfeg/p/9546599.html#_label0

 

51.瀏覽器緩存機制

  • 瀏覽器每次發起請求,都會先在瀏覽器緩存中查找該請求的結果以及緩存標識

  • 瀏覽器每次拿到返回的請求結果都會將該結果和緩存標識存入瀏覽器緩存中

以上兩點結論就是瀏覽器緩存機制的關鍵,它確保了每一個請求的緩存存入與讀取

 

根據是否須要向服務器從新發起HTTP請求將緩存過程分爲兩個部分,分別是強緩存和協商緩存

強緩存:不會向服務器發送請求,直接從緩存中讀取資源,在chrome控制檯的Network選項中能夠看到該請求返回200的狀態碼,而且Size顯示from disk cache或from memory cache。強緩存能夠經過設置兩種 HTTP Header 實現:Expires 和 Cache-Control

強緩存判斷是否緩存的依據來自因而否超出某個時間或者某個時間段,而不關心服務器端文件是否已經更新,這可能會致使加載文件不是服務器端最新的內容,那咱們如何獲知服務器端內容是否已經發生了更新呢?此時咱們須要用到協商緩存策略

協商緩存:用戶發送的請求,發送到服務器後,由服務器斷定是否從緩存中獲取資源

  • 協商緩存生效,返回304和Not Modified
  • 協商緩存失效,返回200和請求結果

協商緩存能夠經過設置兩種 HTTP Header 實現:Last-Modified 和 ETag 。

二者的區別:從名字就能夠看出,強緩存不與服務器交互,而協商緩存則須要與服務器交互。

 

若是什麼緩存策略都沒設置,那麼瀏覽器會怎麼處理?

對於這種狀況,瀏覽器會採用一個啓發式的算法,一般會取響應頭中的 Date 減去 Last-Modified 值的 10% 做爲緩存時間。

 

https://www.jianshu.com/p/54cc04190252

 

52.請求頭header

HTTP請求中的referrer和referrer-policy :http://www.javashuo.com/article/p-kpqqsspu-t.html

 

53.JS中對象和函數的關係

首先什麼是對象?根據W3C上面的解釋JS中全部事物都是對象,對象是擁有屬性和方法的數據,由此能夠看出基本值類型不是對象(number、string、Boolean、undefined、null),剩下的引用類型(函數、數組...)都是對象,也有人說對象是若干屬性的集合。

 

函數和對象是什麼關係?

1.函數是一種對象。很明顯函數是一種對象,但你不能說函數是對象的一種。由於他倆之間是沒有包含關係的。

function test() {};
console.log(test instanceof Object);    //    true

二、對象都是經過函數建立的

先來看一個例子

function test() {
    this.name="哈哈"
};
var test2=new test();
console.log(test2 instanceof Object);    //true

這個例子能夠說明對象能夠被函數建立。那爲何要說對象都是經過函數建立的,那對象字面量是否是也是經過函數來建立的,答案是確定的,這是一種語法糖方式。舉個簡單的例子

var obj={
    name:"哈哈",
    age:"18"
}
var obj=new Object()
obj.name="哈哈";
obj.age="18";

上面的對象字面量實際上是經過下面的構造函數來建立的。而其中的Object是一種函數:

console.log(typeof Object)    //function

經過上面的簡單例子咱們能夠得出一個結論:對象是經過函數建立的,而函數又是一種對象。那麼這是爲何呢?這就牽扯到prototype原型

 

54.null 和 undefeated 的區別?

null是一個表示"無"的對象,轉爲數值時爲0;undefined是一個表示"無"的原始值,轉爲數值時爲NaN

http://www.javashuo.com/article/p-puklnbrk-gm.html

 

55.es6 class

ES6 的 class 屬於一種「語法糖」,因此只是寫法更加優雅,更加像面對對象的編程,其思想和 ES5 是一致的

//定義類
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

等同於

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);

其中 constructor 方法是類的構造函數,是一個默認方法,經過 new 命令建立對象實例時,class必需要用new命令建立,否則會報錯(TypeError: Class constructor Foo cannot be invoked without ‘new’),自動調用該方法。一個類必須有 constructor 方法,若是沒有顯式定義,一個默認的 consructor 方法會被默認添加。因此即便你沒有添加構造函數,也是會有一個默認的構造函數的。通常 constructor 方法返回實例對象 this ,可是也能夠指定 constructor 方法返回一個全新的對象,讓返回的實例對象不是該類的實例

class繼承中,子類必須在constructor方法中調用super方法,不然新建實例時會報錯。這是由於子類本身的this對象,必須先經過父類的構造函數完成塑造,獲得與父類一樣的實例屬性和方法,而後再對其進行加工,加上子類本身的實例屬性和方法。若是不調用super方法,子類就得不到this對象。 

 

super 這個關鍵字,既能夠當作函數使用,也能夠當作對象使用。這兩種狀況下,它的用法徹底不用。

1.看成函數使用

class A {}
class B extends A {
  constructor() {
    super();  // ES6 要求,子類的構造函數必須執行一次 super 函數,不然會報錯。
  }
}

注:在 constructor 中必須調用 super 方法,由於子類沒有本身的 this 對象,而是繼承父類的 this 對象,而後對其進行加工,而 super 就表明了父類的構造函數。super 雖然表明了父類 A 的構造函數,可是返回的是子類 B 的實例,即 super 內部的 this 指的是 B,所以 super() 在這裏至關於 ```A.prototype.constructor.call(this, props)``。

class A {
  constructor() {
    console.log(new.target.name); // new.target 指向當前正在執行的函數
  }
}

class B extends A {
  constructor {
    super();
  }
}
new A(); // A
new B(); // B

能夠看到,在 super() 執行時,它指向的是 子類 B 的構造函數,而不是父類 A 的構造函數。也就是說,super() 內部的 this 指向的是 B

 

2.看成對象使用

在普通方法中,指向父類的原型對象;在靜態方法中,指向父類。

class A {
  c() {
    return 2;
  }
}

class B extends A {
  constructor() {
    super();
    console.log(super.c()); // 2
  }
}
let b = new B();

上面代碼中,子類 B 當中的 super.c(),就是將 super 看成一個對象使用。這時,super 在普通方法之中,指向 A.prototype,因此 super.c() 就至關於 A.prototype.c()。

 

經過 super 調用父類的方法時,super 會綁定子類的 this

class A {
  constructor {
    this.x = 1;
  }
  s() {
    console.log(this.x);
  }
}

class B extends A {
  constructor {
    super();
    this.x = 2;
  }
  m() {
    super.s();
  }
}

let b = new B();
b.m(); // 2

上面代碼中,super.s() 雖然調用的是 A.prototytpe.s(),可是 A.prototytpe.s()會綁定子類 B 的 this,致使輸出的是 2,而不是 1。也就是說,實際上執行的是 super.s.call(this)

因爲綁定子類的 this,因此若是經過 super 對某個屬性賦值,這時 super 就是 this,賦值的屬性會變成子類實例的屬性

  class A {
        constructor() {
            this.x = 1;
        }
    }

    class B extends A {
        constructor() {
            super();
            this.x = 2;
            super.x = 3;
            console.log(super.x); // undefined
            console.log(this.x); // 3
        }
    }

    let b = new B();

上面代碼中,super.x 賦值爲 3,這時等同於對 this.x 賦值爲 3。而當讀取 super.x 的時候,調用的是 A.prototype.x,但並無 x 方法,因此返回 undefined。

 

注意,使用 super 的時候,必須顯式指定是做爲函數,仍是做爲對象使用,不然會報錯。

class A {}
class B extends A {
  constructor() {
    super();
    console.log(super); // 報錯
  }
}

上面代碼中,console.log(super); 的當中的 super,沒法看出是做爲函數使用,仍是做爲對象使用,因此 JavaScript 引擎解析代碼的時候就會報錯。這是,若是能清晰的代表 super 的數據類型,就不會報錯。

最後,因爲對象老是繼承其餘對象的,因此能夠在任意一個對象中,使用 super 關鍵字

https://blog.csdn.net/a419419/article/details/82772412

 

56.JS的運行機制?

https://baijiahao.baidu.com/s?id=1615713540466951098&wfr=spider&for=pc

 

57.函數的防抖和節流

https://www.jianshu.com/p/c8b86b09daf0

 

58.javascript判斷一個字符串或者數組裏面出現最多的元素及其出現的次數

字符串:

  var str = 'aabbccccdddd';

    var obj = {};

    for (var i = 0; i < str.length; i++) {
        if (!obj[str.charAt(i)]) {
            obj[str.charAt(i)] = 1;
        } else {
            obj[str.charAt(i)]++;
        }
    }

    console.log(obj);

    var maxVal = 0;
    var maxStr = '';
    for (var j in obj) {
        if (obj[j] > maxVal) {
            maxVal = obj[j];
            maxStr = j;
        }
    }

    console.log('最多的是:' + maxStr + ',出現了:' + maxVal + '次');

 

數組:

  var arr = [1, 2, 3, 4, 1, 2, 2, 2, 2, 4];

    var obj = {};

    for (var i = 0; i < arr.length; i++) {
        if (!obj[arr[i]]) {
            obj[arr[i]] = 1;
        } else {
            obj[arr[i]]++;
        }
    }

    var maxVal = 0;
    var maxStr = '';

    for (var j in obj) {
        if (obj[j] > maxVal) {
            maxVal = obj[j];
            maxStr = j;
        }
    }
    console.log('最多的是:' + maxStr + ',出現了:' + maxVal + '次');

https://blog.csdn.net/m0_37273490/article/details/80712466

 

59.獲取數組最大值?

    var arr = [1,4,2,0,-2,5];

    var max = Math.max.apply(null, arr);

    var max = Math.max(...arr);

    var max = arr.sort().reverse()[0];

    var max = arr.sort(function (a, b) {
       return b - a;
    })[0];

 

60.HTTP協議

當咱們在瀏覽器地址欄上輸入要訪問的URL後,瀏覽器會分析出URL上面的域名,而後經過DNS服務器查詢出域名映射的IP地址,瀏覽器根據查詢到的IP地址與Web服務器進行通訊,而通訊的協議就是HTTP協議。

https://blog.csdn.net/aliujiujiang/article/details/81088317

 

61.DNS服務

一般咱們訪問一個網站,使用的是主機名或者域名來進行訪問的。由於相對於IP地址(一組純數字),域名更容易讓人記住。但TCP/IP協議使用的是IP地址進行訪問的,因此必須有個機制或服務把域名轉換成IP地址。DNS服務就是用來解決這個問題的,它提供域名到IP地址之間的解析服務。

  

 

62.HTTP與TCP/IP、DNS的關係

HTTP協議與它們之間的關係:

HTTP與TCP/IP、DNS的關係
當客戶端訪問Web站點時,首先會經過DNS服務查詢到域名的IP地址。而後瀏覽器生成HTTP請求,並經過TCP/IP協議發送給Web服務器。Web服務器接收到請求後會根據請求生成響應內容,並經過TCP/IP協議返回給客戶端。

 

63.箭頭函數

引入箭頭函數有兩個方面的做用:更簡短的函數而且不綁定this

箭頭函數表達式的語法比函數表達式更簡潔,而且沒有本身的thisargumentssuper或 new.target

這些函數表達式更適用於那些原本須要匿名函數的地方,而且它們不能用做構造函數。 

箭頭函數不會建立本身的this,它只會從本身的做用域鏈的上一層繼承this

箭頭函數沒有prototype屬性。

因爲 箭頭函數沒有本身的this指針,經過 call() 或 apply() 方法調用一個函數時,只能傳遞參數(不能綁定this),他們的第一個參數會被忽略。(這種現象對於bind方法一樣成立)

 

不斷完善...

相關文章
相關標籤/搜索