一.單線程和異步的關系
- 單線程:同一時間只能做一件事
- 原因:避免DOM渲染的沖突
- 解決方案:異步
- 實現方式--event loop
1.什么是單線程,和異步的關系
單線程:同一時間,只能做一件事,<span style="color:red">正是因為js 是單線程,才出現了異步解決方案</span>,
像定時器,如果沒有異步的話,頁面就一直卡在那等著,所以說,異步是唯一而高效的解決方案2.js為什么是單線程
? <span style="color:red">原因避免DOM渲染沖突</span>:
- 瀏覽器需要渲染DOM
- JS可以修改DOM結構
- js執行的時候,瀏覽器DOM渲染會暫停
- 兩段js也不能同時執行(都修改DOM就沖突了)
- webworker支持多線程,但是不能訪問DOM
3.異步帶來了哪些問題
- 問題一:沒有按照書寫方式執行,可讀性差
- 問題二:callback中不容易模塊化
4. 實現異步的方式--eventloop
- 事件輪詢,js實現異步的具體的解決方案
- 同步代碼,直接執行
- 異步函數先放在異步隊列中
- 待同步函數執行完畢,輪詢執行異步隊列的函數
5.Promise的基本使用
- 異常捕獲
//規定:then只接受一個參數,最后統一用catch捕獲異常 resutl.then(function(img){ console.log(img.width) }).then(function(img){ console.log(img.width) }).catch(function(ex){ //最后統一 catch console.log(ex) })
- Promise.all和Promise.race
image.png
- Promise標準
image.png6.async/await
- then只是將callback拆分了
image.png
- async/await 是最直接的同步寫法
[圖片上傳失敗...(image-86d1c6-1595464164685)]
- 用法
[圖片上傳失敗...(image-138a79-1595464164686)]
二.js垃圾回收機制
1.堆棧溢出
? 當存儲的數據達到某一限制就會造成堆棧溢出
2. 內存泄漏
? 當不斷向堆中存儲數據,而不進行清理,這就是內存泄漏
3.垃圾回收
? 語言一般分為兩種,一種自動清理,一種手動清理,js只有自動清理
現在各大瀏覽器通常用采用的垃圾回收有兩種方法:標記清除、引用計數。
標記清除
js中最常用的垃圾回收方式就是標記清楚,當變量進入環境時,就標記這個變量為“進入環境“,當變量離開環境時,就將其標記為”離開環境“。 被標記離開環境的變量在下一次垃圾回收啟動的時候會被釋放掉占用的內存空間
引用計數
引用計數的含義是跟蹤記錄每個值被引用的次數。當聲明了一個變量并將一個引用類型賦值給該變量時,則這個值的引用次數就是1。相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值的引用次數就減1。當這個引用次數變成0時,則說明沒有辦法再訪問這個值了,因而就可以將其所占的內存空間給收回來。這樣,垃圾收集器下次再運行時,它就會釋放那些引用次數為0的值所占的內存。
- 垃圾回收機制觸發條件
IE6的垃圾回收機制是根據內存分配量允許的,當環境中的256個變量,4096個對象,64k的字符串任意一張情況的時候都會觸發垃圾回收器工作,bug!!
IE7中做了調整,觸發條件不再是固定的多,而是動態修改的,初始值和IE6相同,如果垃圾回收器回收的內存分配量低于程序占用內存的15%,說明大部分內存不可被回收,設的垃圾回收觸發條件過于敏感,這時候把臨界條件翻倍,如果回收的內存高于85%,說明大部分內存早就該清理了,這時候就把觸發條件置回
三 渲染機制
1.Doctype的作用是什么?
作用是為了告訴瀏覽器該文件的類型。讓瀏覽器解析器知道應該用哪個規范來解析文檔 html5 <!Doctype html> HTML 4.01 Strict <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> HTML 4.01 Transitional <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2.瀏覽器渲染過程
image.png?
? HTML渲染大致分為如下幾步:
HTML被HTML解析器解析成DOM Tree, css則被css解析器解析成CSSOM Tree。
DOM Tree和CSSOM Tree解析完成后,被附加到一起,形成渲染樹(Render Tree)。
節點信息計算(重排)也叫回流,這個過程被叫做Layout(Webkit)或者Reflow(Mozilla)。即根據渲染樹計算每個節點的幾何信息(DOM對象的位置和尺寸大小),并將其安置在界面中的正確位置
渲染繪制(重繪),這個過程被叫做(Painting 或者 Repaint)。即根據計算好的信息繪制整個頁面。
以上4步簡述瀏覽器的一次渲染過程,理論上,每一次的dom更改或者css幾何屬性更改,都會引起一次瀏覽器的重排/重繪過程,而如果是css的非幾何屬性更改,則只會引起重繪過程。所以說重排一定會引起重繪,而重繪不一定會引起重排。
觸發重排的操作有:
? 當你增加/刪除/修改DOM節點時,會導致重排/重繪
? 當你移動DOM的位置
? 當你resize窗口的時候(移動端沒有這個問題)
? 元素尺寸的改變
? 當你修改網頁默認字體時
觸發重繪的操作有:
? 相比重排,重繪就簡單多了,所謂重繪,就是當頁面中元素樣式的改變并不影響
? 它在文檔流中的位置時,例如更改了字體顏色,瀏覽器會將新樣式賦予給元素并重新繪制的過程稱。
color border-style visibility background text-decoration background-image background-position background-repeat outline-color outline outline-style border-radius outline-width box-shadow background-size [圖片上傳失敗...(image-491d9d-1595464164686)]
image.png3.為什么操作 DOM 慢
? 因為 DOM 是屬于渲染引擎中的東西,而 JS 又是 JS 引擎中的東西。當我們通過 JS 操作 DOM 的時候,其 實這個操作涉及到了兩個線程之間的通信,那么勢必會帶來一些性能上的損耗。操作 DOM 次數一多,也 就等同于一直在進行線程之間的通信,并且操作 DOM 可能還會帶來重繪回流的情況,所以也就導致了性 能上的問題。
四 頁面性能類
題目:提升頁面性能的方法有哪些
資源壓縮合并,減少HTTP請求
非核心代碼異步加載->異步加載的方式->異步加載的區別
1.異步加載的方式 1)動態腳本加載 2)defer 3)async 2.異步加載的區別 1)defer是在html解析完成后才會執行,如果是多個,按照加載的順序依次執行 2)async是在加載完之后立即執行,如果是多個,執行順序和加載順序無關
- 利用瀏覽器緩存->緩存的分類->緩存的原理
1.緩存的策略 1)強緩存:就是在緩存有效期內直接使用緩存 Expires是HTTP/1.0控制網頁緩存的字段,其值為服務器返回該請求結果緩存的到期時間,即在此發起該請 求 時,如果客戶端的時間小于Expires的值時,直接使用緩存結果。 在HTTP/1.1中,使用Cache-Contro cache-control: max-age=600 expires: Mon, 16 Apr 2018 01:41:50 GMT 2)協商緩存: 協商緩存就是強制緩存失效后,瀏覽器攜帶緩存標識想服務器發起請求, 由服務器根據緩存標識決定是否使用緩 存的過程,主要有以下兩種情況: 協商緩存生效,返回304,即數據未更改可以繼續使用。 協商緩存失效,返回200,數據已發生更改,并返回客戶端新的數據。 Last-Modified / If-Modified-Since ETag
使用CDN
預解析DNS
<link rel="dns-prefetch" > 當遇到a標簽但是為了確保安全性,在HTTPS頁面中不會自動解析 希望在HTTPS頁面開啟自動解析功能時,添加如下標記 <meta http-equiv="x-dns-prefetch-control" content="on">
五. vue和react的區別
相同點
? 1.都支持服務器端渲染
**2.都有Virtual DOM,組件化開發,通過props參數進行父子組件數據的傳遞,**
? 都實現webComponent規范
? 3.數據驅動視圖
? 4.都有支持native的方案,React的React native,Vue的weex
? 5.都有管理狀態,React有redux,Vue有自己的Vuex(自適應vue,量身定做)
? 6.只有框架的骨架,其他的功能如路由/狀態管理等是與框架分離的
? 7.都是javascript的UI框架,數據驅動試圖
不同點
**1.React嚴格上只針對MVC的view層,Vue則是MVVM模式**
? 2.virtual DOM不一樣,vue會跟蹤每一個組件的依賴關系,不需要重新渲染整個組件樹.
? 而對于React而言,每當應用的狀態被改變時,全部組件都會重新渲染,
? 所以react中會需要shouldComponentUpdate這個生命周期函數方法來進行控制
**3.組件寫法不一樣, React推薦的做法是 JSX + inline style, **
? 也就是把HTML和CSS全都寫進JavaScript了,即'all in js';
? 通過js來生成html,所以設計了jsx,還有通過js來操作css,社區的styled-component、jss等
? Vue推薦的做法是
webpack+vue-loader
的單文件組件格式,即html,css,jd寫在同一個文件;**4.數據綁定: vue實現了數據的雙向綁定,react數據流動是單向的** **5.state對象在react應用中不可變的,需要使用setState方法更新狀態;**
? 在vue中,state對象不是必須的,數據由data屬性在vue對象中管理;
**6.多了指令系統,讓模版可以實現更豐富的功能,而React只能使用JSX語法;**
? 7.vue基于數據劫持,攔截到最新的數據,從而渲染視圖,
? react是提供對應的API,通過我們操作API,讓最新數據渲染視圖
? 8.react默認只實現了單向控制(只有數據影響視圖),
? 而vue基于v-model實現了雙向控制(即也包含了視圖影響數據)
? 無論vue還是react,在實現視圖影響數據的方式上,也都是基于change/input事件,
? 監聽表單元素內容的改變,從而去修改數據,達到數據的更新
vue和react選擇
- vue:最新文檔和更簡單的語法,更小,更快,更靈活。豐富的html模版,易于開發
- react:需要構建移動應用程序,專業和出色的社區支持,以解決任何問題。需要構建大型應用程序,輕量級,易于版本歉意
6.MVC(后端node)與前端MVVM之間的區別
MVC 是后端的分層開發概念
MVVM 是前端視圖層的概念,主要關注于視圖層分離,也就是說:MVVM把前端的視圖層,分為了三部分Model,View,ViewModel(VM),其中VM是MVVM思想的核心:因為VM是M和V之間的調度者
MVVM的思想,主要是為了讓我們開發者更加方便,因為MVVM提供了數據的雙向綁定;
注意:數據的雙向綁定是由VM提供的;
image.png<body> <!-- Vue實例所控制的這個元素區域,就是MVVM中的 V --> <div id="app"> <div >{{message}}</div> </div> <script> // new出來的這個VM對象,就是我們MVVM中的 VM 調度者 var vm = new Vue({ el: "#app", // 這里的data就是MVVM中的 M,專門用來保存每個頁面的數據的 data: { message: "hello world", } }) </script> </body>
vue
vdom
- vdom是什么?為何會存在vdom?
虛擬dom,用js模擬DOM結構, DOM操作非常”昂貴“,將DOM對比操作放在js層,提高效率 由于在瀏覽器中操作DOM是很昂貴的。頻繁的操作DOM,會產生一定的性能問題。這就是虛擬Dom的產生原因
- key的作用
key得作用主要是為了高效的更新虛擬DOM,其原理是vue在patch過程中通過可以精確判斷兩個節點是否是同一個,從而避免頻繁更新不同元素,使得整個patch過程更加高效,減少DOM操作量,提高性能
vue 2.0 響應式原理
//Vue 2.0 實現相應式原理 //數據變化了,可以更新視圖 let oldArrayPrototype = Array.prototype let proto = Object.create(oldArrayPrototype); ['push','shift','unshift'].forEach(method => { proto[method] = function(){ oldArrayPrototype[method].call(this,...arguments) updateView(); } }); function observer(target){ if(typeof target !== 'object' || target == null){ return target } if(Array.isArray(target)){//攔截數組,給數組的方法進行了重寫 target.__proto__ = proto } for(let key in target){ defineReactive(target,key,target[key]) } } function defineReactive(target,key,value){ observer(value) //遞歸 Object.defineProperty(target,key,{ get(){ return value }, set(newValue){ if(newValue !== value){ observer(newValue) updateView(); value = newValue } } }) } function updateView(){ console.log('更新視圖'); } let data = {name:'zf',age:{n:200},arr:[0,1,2]} observer(data) data.arr.push(3)
VUE3.0 響應原理
function trigger() { console.log('觸發視圖更新'); } function isObject(target) { return typeof target == 'object' && target !== null; } function reactive(target) { if (!isObject(target)) { return target } const handlers = { set(target, key, value) { if (target.hasOwnProperty(key)) { trigger(); } return Reflect.set(target, key, value); }, get(target, key, receiver) { const res = Reflect.get(target, key) if (isObject(target[key])) { return reactive(res) //遞歸 } return res; }, deleteProperty(target, key) { return Reflect.deleteProperty(target, key) } } let observed = new Proxy(target, handlers) return observed } let obj = { name: 'zf', a: [1, 2, 3] } let p = reactive(obj) p.a.push(4)
react
ref
ajax:
異步組件:按需家長
其他面試題
1.進程和線程
https://www.php.cn/faq/418138.html
2.節流和防抖
http://www.lxweimin.com/p/757957750792
3.頁面布局的方式
流式布局,也叫百分比布局
流式布局的特征:
寬度自適應,高度寫死,并不是百分百還原設計圖。
圖標都是固定死大小的,包括字體等也是固定死的。并不是所有的東西都是自適應的。
一些大的圖片,設置寬度為百分比自適應即可,隨著屏幕大小進行變化,對于小圖標或者文本等, 一般都是定死寬高大小。
等比縮放 rem
響應式布局
4.instance of 原理
<script type="text/javascript">
//自定義一個構造函數
function Fun(){}
//利用上面的構造函數構造一個實例
var fun1 = new Fun()
console.log(fun1 instanceof Fun) //true
console.log(fun1 instanceof Function) //false
console.log(fun1 instanceof Object) //true
</script>
Instanceof運算符的第一個變量是一個對象,暫時稱為A;第二個變量一般是一個函數,暫時稱為B。
Instanceof的判斷規則是:沿著A的__proto__這條線來找,同時沿著B的prototype這條線來找,如果兩條 線能找到同一個引用,即同一個對象,那么就返回true。如果找到終點還未重合,則返回false。
5.普通函數中的和箭頭函數this
箭頭函數和普通函數的區別如下。
普通函數:根據調用我的人(誰調用我,我的this就指向誰)
箭頭函數:根據所在的環境(我再哪個環境中,this就指向誰)
一針見血式總結:
普通函數中的this:
1. this總是代表它的直接調用者(js的this是執行上下文), 例如 obj.func ,那么func中的this就是obj
2.在默認情況(非嚴格模式下,未使用 'use strict'),沒找到直接調用者,則this指的是 window (常見的window的屬 性和方法有: alert, location,document,parseInt,setTimeout,setInterval等)(約定俗成)
3.在嚴格模式下,沒有直接調用者的函數中的this是 undefined
4.使用call,apply,bind(ES5新增)綁定的,this指的是 綁定的對象
ES6箭頭函數中this
(1)默認指向定義它時,所處上下文的對象的this指向。即ES6箭頭函數里this的指向就是上下文里對象this指向,偶爾沒有上下文對象,this就指向window
(2)即使是call,apply,bind等方法也不能改變箭頭函數this的指向
6.http中服務狀態碼?303,301,302的區別?
HTTP狀態碼301與302有什么區別2,515次閱讀
301:(永久移動)請求的網頁已被永久移動到新位置。服務器返回此響應(作為對GET或HEAD請求的響應)時,會自動將請求者轉到新位置。
302:(臨時移動)服務器目前正從不同位置的網頁響應請求,但請求者應繼續使用原有位置來進行以后的請求。此代碼與響應GET和HEAD請求的301代碼類似,會自動將請求者轉到不同的位置。
HTTP狀態碼301與302的區別:
1、它們之間關鍵區別在,資源是否存在有效性;
2、301資源還在只是換了一個位置,返回的是新位置的內容;
3、302資源暫時失效,返回的是一個臨時的代替頁上。
304(未修改)
注意:如果永久失效建議使用404
7.http的緩存機制
https://www.cnblogs.com/chenqf/p/6386163.html
對于強制緩存,服務器通知瀏覽器一個緩存時間,在緩存時間內,下次請求,直接用緩存,不在時間內,執行比較緩存策略。
Expires
Expires的值為服務端返回的到期時間,即下一次請求時,請求時間小于服務端返回的到期時間,直接使用緩存數據。
不過Expires 是HTTP 1.0的東西,現在默認瀏覽器均默認使用HTTP 1.1,所以它的作用基本忽略。
另一個問題是,到期時間是由服務端生成的,但是客戶端時間可能跟服務端時間有誤差,這就會導致緩存命中的誤差。
所以HTTP 1.1 的版本,使用Cache-Control替代。
Cache-Control:max-age=1000
Cache-Control
Cache-Control 是最重要的規則。常見的取值有private、public、no-cache、max-age,no-store,
默認為private。
private: 客戶端可以緩存
public: 客戶端和代理服務器都可緩存(前端的同學,可以認為public和private是一樣的)
max-age=xxx: 緩存的內容將在 xxx 秒后失效
no-cache: 需要使用對比緩存來驗證緩存數據(后面介紹)
no-store: 所有內容都不會緩存,強制緩存,對比緩存都不會觸發(對于前端開發來說,緩存越多越好, so...基本上和它說886)
對于協商緩存,將緩存信息中的Etag/If-None-Match和Last-Modified/If-Modified-Since通過請求發送給服務器,由服務器校驗,返回304狀態碼時,瀏覽器直接使用緩存。
Cache-Control:no-cache
http緩存控制
1.http緩存能夠幫助服務器提高并發性能,很多資源不需要重復請求直接從瀏覽器中拿緩存
2.http緩存分類:強緩存 協商緩存
3.強緩存通過expires和cache-control控制 ,協商緩存通過last-Modify 和E-tag控制
補充:
1.為什么有expires 還需要cache-control
因為expires有個服務器和瀏覽器時間不同步的問題
expires是絕對時間 cache-control是相對時間
2.last-modify 和 etag
last-modify 它是有個精度問題到秒
e-tag沒有精度問題, 只要文件改變 e-tag值就改變
8.對原型和作用域鏈的理解
原型:
所有的函數都天生自帶一個屬性:prototype(原型),它是一個對象數據類型的值,在當前prototype對象中,存儲了類需要給其實例使用的公有的屬性和方法
prototype這個對象,瀏覽器會默認為其開一個堆內存,這個堆內存中天生自帶一個屬性:constructor(構造函數),這個屬性存儲的的值就是當前函數本身
每一個類的實例(每一個對象)都天生自帶一個屬性:proto,屬性值是當前對象所屬類的原型(prototype)
原型鏈:
當試圖得到一個對象的某個屬性時,如果這個對象本身沒有這個屬性,那么會去它的proto(即它的構造函數的prototype)中尋找,即
console.log(obj.__proto__ === Object.prototype);
作用域鏈:(當前作用域沒有定義某個變量,所以要去它的父級作用域找,這樣的就是作用域鏈)
當前作用域代碼執行的時候遇到一個變量,首先看一下它是否屬于私有變量,
如果不是私有變量,向其上級作用域查找,也不是上級作用域私有變量,繼續向上查找,
一直到window全局作用域為止,
我們把這種向上一級級查找機制叫做作用域鏈
9.redux
1.store通過reducer創建了初始狀態,因為創建容器的時候執行一次DISPATCH
3.用戶產生了操作,發送一個action對象到store的dispatch函數里面
4.然后會調用reducer,reducer接收到action并根據action.type去匹配,執行相應的邏輯,返回新的state
5.store.subscribe方法里的回調函數會執行,此時就可以通知view去重新獲取state
(通知事件池中的方法依次執行)
2.view通過store.getState()獲取到了store中保存的state掛載在了自己的狀態上
redux是如何降state注入到react組件上去
1.首先明確與React產生關聯的React-redux這個庫
2.Redux的原理就是一個發布訂閱器,幫我買用一個變量存儲所有的state,并且提供了發布功能來修改數據,以及訂閱功能 來觸發回調
3.而React-Redux的作用就是訂閱Store里數據的更新,他包含兩個重要元素,Provider和connect方法
4.Provider的作用就是通過Context API把 Store對象注入到React組件上去
5.而Connect方法就是一個高階組件,在高階組件里通過訂閱Store中數據的更新,從而通過調用 setState方法來觸發
組件更新
redux 最大的弊端是樣板代碼太多,修改數據的鏈路太長
解決方案:可借助一些工具,幫我嗎減少創建代碼的過程,Redux-Actions
10.事件訂閱
訂閱發布模式定義了一種一對多的依賴關系,讓多個訂閱者對象同時監聽某發布者對象。
這個發布者對象在自身狀態變化時,會通知所有訂閱者對象,使它們能夠自動更新自己的狀態。
class Public{
constructor(){
this.handlers = {}
}
on(eventType,handler){
if(!(eventType in this.handlers)){
this.handlers[eventType] = []
}
this.handlers[eventType].push(handler)
}
emit(eventType){
if(!(eventType in this.handlers)){
return
}
let handlers = this.handlers[eventType]
for(let i=0;i<handlers.length;i++){
handlers[i]()
}
}
off(eventType,fn){
if(!(eventType in this.handlers)){
return
}
let currentHandler = this.handlers[eventType]
let length = currentHandler.length
for(let i=length-1;i>=0;i--){
if(fn === currentHandler[i]){
currentHandler.splice(i,1)
}
}
if(currentHandler.length === 0 ){
delete this.handlers[eventType]
}
}
}
let publish = new Public()
let fn = ()=>{
console.log(1);
}
fn1 = ()=>{
console.log(2);
}
fn2 = ()=>{
console.log(3);
}
11.如何檢測一個數組
array.isArray判斷,返回true,說明是數組
instanceof Array判斷,返回true。說明是數組
12 .vue數據響應式原理
vue.js 則是采用數據劫持+發布訂閱模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變動時發布消息給訂閱者,觸發相應的監聽回調
13.前端路由
什么是路由?
根據不同的url地址展示不同的頁面或者數據
路由分為前端路由和后端路由
前端路由:
1.前端路由多用于單頁面開發,也就是SPA
2.前端路由不涉及到服務器的,是前端利用hash或者HTML5的historyApi來實現的,一般用于不同的內容展示和切換
后端路由:
通過用戶請求的url導航到具體的html頁面;每跳轉到不同的URL,都是重新訪問服務端,然后服務端返回頁面,頁面也可以是服務端獲取數據,然后和模板組合,返回HTML,也可以是直接返回模板HTML,然后由前端js再去請求數據,使用前端模板和數據進行組合,生成想要的HTML
14.用過哪些的loader和plugins
loader:
style-loader、
css-loader、
sass-loader
file-loader 、
url-loader
babel-loader
vue-loader
plugins:
mini-css-extract-plugin //將css文件提取為獨立的文件的插件
html-webpack-plugin //將模板文件和js文件整合到一塊
clean-webpack-plugin //清理文件
UglifyJSPlugin
DllPlugin
ParallelUglifyPlugin
15.為什么require是在哪引入都可以,而import必須在文件最前面引入?
require是運行時調用,所以require理論上可以運用在代碼的任何地方
import是編譯時調用,所以必須放在文件開頭
16.對babel的了解
Babel是一個JavaScript編譯器
Babel是一個工具鏈,主要用于將ECMAScript 2015+版本的代碼轉換為向后兼容的JavaScript語法,可以使之運行在當前和舊版本的瀏覽器或其他環境中。
下面列出的是Babel能為你做的事情:
語法轉換
通過Polyfill方式在目標環境中添加缺失的特性(通過@ babel / polyfill模塊)
原始碼轉換(codemods)
17.前端模塊化方案
CommonJS 是服務器模塊的規范,Node.js采用了這個規范 同步加載
AMD(require.js) 專門用于瀏覽器端,模塊的加載是異步
CMD(sea.js) 按需加載
ES6 瀏覽器端,js語言本身的
18.node的核心模塊
http、https、fs、qs、path url querystring
19.new操作符干了什么
var Func=function(){
this.name='www'
};
var func=new Func ();
new共經過了4幾個階段
1、創建一個空對象
varobj=new Object();
2、設置原型鏈
obj.__proto__= Func.prototype;
3、讓Func中的this指向obj,并執行Func的函數體。
var result =Func.call(obj);
4、判斷Func的返回值類型:
如果是值類型,返回obj。如果是引用類型,就返回這個引用類型的對象。
if (typeof(result) == "object"){
func=result;
}
else{
func=obj;;
}
20.內存溢出和內存泄漏
內存溢出:
一種程序運行出現的錯誤
當程序運行需要的內存超過了剩余的內存時,就拋出了內存溢出的錯誤
內存泄漏:
占用的內存沒有及時釋放
內存泄漏積累多了就容易導致內存溢出
常見的內存泄漏:
意外的全局變量
沒有及時清理的定時器
必包
21.http與https的區別
1、https協議需要到CA (Certificate Authority,證書頒發機構)申請證書,
2、http是超文本傳輸協議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協議。
3、http和https使用的端口也不一樣,前者是80,后者是443。
22.fetch 和 axios區別
fetch 是一個底層的api,瀏覽器原生支持的
axios 是一個封裝好的框架
axios:axios函數就是把發送ajax 用promise封裝了一下
1)支持瀏覽器和nodejs發請求 前后短發請求
2)支持promise語法
3)支持自動解析json
4)支持請求進度檢測
fetch
優點:
1)瀏覽器級別原生支持的api
2)原生支持的promise api
3)語法簡潔
缺點:
1)不支持文件上傳進度檢測
2)使用不完美,需要封裝
3)默認不帶cookie
4)需要手動處理返回的數據
23.輸入 URL 到頁面渲染的整個流程
1.對域名進行解析,得到ip地址
2.根據ip地址,找到服務器,發起TCP的三次握手
3.建立TCP連接后發起http請求
4.服務器響應HTTP請求,瀏覽器得到html代碼
5.瀏覽器解析html代碼,并請求html代碼中的資源(如:js/css/圖片)
6.瀏覽器對頁面進行渲染呈現給用戶
7服務器關閉連接
1)HTML被HTML解析器解析成DOM Tree, css則被css解析器解析成CSSOM Tree。
如果遇到 script 標簽的話,會判斷是否存在 async 或者 defer ,前者會并行進行下載并執行 JS,后者會先下載文 件,然后等待 HTML 解析完成后順序執行。
如果以上都沒有,就會阻塞住渲染流程直到 JS 執行完畢。遇到文件下載的會去下載文件
2)DOM Tree和CSSOM Tree解析完成后,被附加到一起,形成渲染樹(Render Tree)。
3)節點信息計算(重排)也叫回流,這個過程被叫做Layout(Webkit)或者Reflow(Mozilla)。即根據渲染樹計算每個節點的 幾何信息(DOM對象的位置和尺寸大小),并將其安置在界面中的正確位置
4)渲染繪制(重繪),這個過程被叫做(Painting 或者 Repaint)。即根據計算好的信息繪制整個頁面。
24.xss 和 csrf
1.xss 跨站腳本攻擊
2.xss 瀏覽器向服務器請求的時候被注入腳本攻擊
防范手段:
輸入過濾
html字符轉譯
2. csrf 跨站請求偽造
黑客通過網站B,誘使用戶去訪問已經登錄了的網站A,進行一些違背用戶意愿的請求,造成用戶損失
防范手段:
請求的時候,加token
25.async/await
async/await使得異步代碼看起來像同步代碼,這正是它的魔力所在
async +await 原理 generate+yield
async 函數是什么?一句話,它就是 Generator 函數的語法糖。
Generator 函數是 ES6 提供的一種異步編程解決方案,語法行為與傳統函數完全不同。本章詳細介紹 Generator 函數的語法和 API,它的異步編程應用請看《Generator 函數的異步應用》一章。
26.清除浮動的方法
1.父級div定義偽類:after
.clearfloat:after{display:block;clear:both;content:"";visibility:hidden;height:0}
2.在結尾處添加空div標簽clear:both
原理:添加一個空div,利用css提高的clear:both清除浮動,讓父級div能自動獲取到高度
優點:簡單,代碼少,瀏覽器支持好,不容易出現怪問題
缺點:不少初學者不理解原理;如果頁面浮動布局多,就要增加很多空div,讓人感覺很不爽
3.父級div定義height
原理:父級div手動定義height,就解決了父級div無法自動獲取到高度的問題
優點:簡單,代碼少,容易掌握
缺點:只適合高度固定的布局,要給出精確的高度
4.父級div定義overflow:hidden/auto
原理:觸發BFC,浮動元素的高度也參與計算
27.BFC
BFC 全稱為 塊格式化上下文 (Block Formatting Context) 。
觸發BFC規范的元素,可以形成一個獨立的容器。不收到外界的影響,從而解決一些布局的問題
如何創建BFC
1、float的值不是none。
2、position的值不是static或者relative。
3、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
4、overflow的值不是visible
BFC特性及應用
解決margin疊加問題
解決margin傳遞問題
解決浮動問題
解決覆蓋問題
28.元素水平垂直居中
.box{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
.box{
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
.parent{
display: flex;
justify-content: center;
align-items: center;
}
29.ES6 新特性
(1)新增聲明命令let和const
(2)模板字符串(Template String)
(3)函數的擴展
函數的默認參數
箭頭函數
(4)對象的擴展
屬性的簡寫。ES6 允許在對象之中,直接寫變量。這時,屬性名為變量名, 屬性值為變量的值
方法的簡寫。省略冒號與function關鍵字
(6)import和export ES6標準中,JavaScript原生支持模塊(module)了
(7)Promise對象
(8)解構賦值
(10)展開運算符(...)
30 事件冒泡和事件捕獲
事件冒泡 事件冒泡:事件會從最內層的元素開始發生,一直向上傳播,直到document對象。
事件捕獲 事件捕獲:與事件冒泡相反,事件會從最外層開始發生,直到最具體的元素。 第一個參數是需要綁定的事件,第二個參數是觸發事件后要執行的函數。而第三個參數默認值是false,表示在事件冒泡的階段調用..
31.js如何解決異步的
回調函數
事件觸發
發布/訂閱者模式
promise
generate
32 promise
class MyPromise{
constructor(exec){
this.status = "pending"
this.value = undefined
this.resolveArr = []
this.rejectArr = []
let change = (status,value)=>{
if(this.status !== "pending") return
this.status = status
this.value = value
let fnArr = this.status === 'resolve' ? this.resolveArr : this.resolveArr
fnArr.forEach((item)=>{
if(typeof item !== 'function'){
return
}
item(this.value)
})
}
let resolve = (value)=>{
if(this.rejectArr.length > 0){
change('resolve',value)
}
let timer = setTimeout(()=>{
change('resolve',value)
clearTimeout(timer)
},0)
}
let reject = (value)=>{
if(this.rejectArr.length > 0){
change('reject',value)
}
let timer = setTimeout(()=>{
change('reject',value)
clearTimeout(timer)
},0)
}
try{
exec(resolve,reject)
}catch(err){
reject(err.message)
}
}
then(resolve,reject){
this.resolveArr.push(resolve)
this.rejectArr.push(reject)
}
}
new MyPromise((resolve, reject) => {
setTimeout(_ => {
resolve(100);
//reject('ERROR');
}, 1000);
}).then(result => {
console.log(result);
})
33.深復制
function cloneObject(target,source){
var names = Object.getOwnPropertyNames(source)
for(let i=0;i<names.length;i++){
var desc = Object.getOwnPropertyDescriptor(source,names[i])
if(typeof desc.value == 'object' && desc.value !==null){
switch(desc.value.constructor){
case RegExp:
obj = new desc.value.constructor(desc.value.source,desc.value.flags)
break;
default:
obj = new desc.value.constructor()
}
cloneObject(obj,desc.value)
Object.defineProperty(target,names[i],{
value:obj,
enumerable:desc.enumerable,
writable:desc.writable,
configurable:desc.configurable
})
}else{
Object.defineProperty(target,names[i],desc)
}
}
return target
}
性能優化
初始階段->加載優化
- 首頁加載慢的優化
問題分析
- 首頁加載圖片過多
- 首頁的請求量過多
- 首頁請求的靜態資源(html/css/js/圖片)過大
結論:所有加載慢的問題最終都可以歸納成兩個問題 多和大
Q:首頁加載圖片過多的問題,可以通過以下幾種方法解決:
1)通過懶加載的方式處理非首屏的圖片
2)對于小圖標可以采用iconfont的方式解決
3)對于小圖片可以采用雪碧圖的方式解決
Q:首頁的請求量過多怎么解決?
如何分析:
1.先通過瀏覽器的Network可以確定首頁加載的資源和請求量
- request:請求數量
- resources:前端資源總大小
- DOMContentLoaded:瀏覽器已經完全加載了HTML,其他靜態資源(js,css,圖片等)
- load:瀏覽器已經加載了所有的靜態資源
2.通過converge來查看代碼的使用狀況
- 只針對js和css
- 可以看出哪些代碼雖然加載了但是沒有執行
- 沒有執行的代碼可以考慮一下是否可以懶加載
A:可以通過減少資源的請求量
- 通過nginx服務器來做資源文件合并--將多個js/css文件合并成一個(nginx 添加nginx-http-concat模塊)
- 通過打包工具來做資源文件的物理打包
總結
? 1)通過nginx服務器來做資源文件的合并或者通過webpack等打包工具進行物理打包
? 2) 在代碼層面,對于需要引入一些大型第三方庫的時候,可以通過特定的Babel插件來進行按需加載
? 3)還有可以使用react lazy或其他動態導入方案來進行前端路由層面的動態加載,從而可以減少
? 首頁的js和css的大小
答題思路
對于首頁加載慢的問題,一般是由于加載資源過多,并且資源過大導致。 所以應對的策略就減少資源的數量以及減小資源的大小 1)對于圖片可以懶加載,減少首屏圖片加載量。小圖片使用雪碧圖來解決,最大程度減少首屏圖片數量,從而提升 首頁渲染性能 2)對于其他資源可以通過打包(nginx-http-concat或者webpack打包)來合并資源,并可以通過懶加載路由的方 式來減小首頁js的加載量 3)減小資源的方式可以通過壓縮和混淆加密來減小文件體積,圖片可以使用工具來壓縮或者使用webp格式 4)同時可在服務器開始gzip壓縮來最大化減少所有文件體積
- 優化圖片的做法
1)可以通過懶加載減少圖片的請求,或者通過雪碧圖來合并圖片,以及將小圖轉化成base64的格式,來解決請多的 問題 2)圖片大的問題,可以通過自動化壓縮工具來壓縮圖片,或者使用webp格式的圖片
實現webpack打包優化
實現CDN加速
CDN 服務器主要是用來放靜態資源的服務器,可以用來加速靜態資源的下載 CDN 之所以能夠加速,是因為會在很多地方都部署 CDN 服務器,如果用戶需要下載靜態資源,會自動選擇最近的節點下載 同時由于 CDN 服務器的地址一般都跟主服務器的地址不同,所以可以破除瀏覽器對同一個域名發送請求的限制
函數的副作用
結構復制。。。
hooks
dea
set map