您好,登錄后才能下訂單哦!
這篇文章主要介紹“web前端常見面試題實例分析”,在日常操作中,相信很多人在web前端常見面試題實例分析問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”web前端常見面試題實例分析”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
在js語言中,每個實例對象都有一個__proto__
屬性,改屬性指向他的原型對象,且這個實例對象的構造函數都有一個原型屬性prototype
,與實例對象的__proto__屬性指向同一個對象,當這個對象在查找一個屬性的值時,自身沒有就會根據__proto__向他的原型
上尋找,如果不存在,則會到生成這個實例對象的構造函數的原型對象上尋找,如果還是不存在,就繼續道Object的原型對象上找,在往上找就為null了,這個鏈式尋找的過程,就被稱為原型鏈
。
首先從構造函數說起,構造函數通過prototype
指向他的原型對象,原型對象通過他的constructor
屬性指回這個構造函數,表明原型對象是由哪個構造函數生成的。原型對象通過new關鍵字生成的實例對象,這個實例對象可以通過__proto__
屬性指向生成這個實例對象的構造函數的原型對象,實現一個三角關系。
繼承的方式有很多種,網上的答案都有很多,我自己總結且大致說的明白的有這五種
1)原型鏈繼承
借助原型可以基于已有的對象創建對象,同時還不必因此創建自定義類型。 在 object()函數內部,先創建一個臨時的構造函數,然后將傳入的對象作為這個構造 函數的原型,最后返回了這個臨時類型的一個新實例。關鍵代碼:Star.proyotype = new Person(), Star.proyotype.constructor = Star
缺點:只能繼承父類的方法
2)借用構造函數繼承
在子類構造函數的內部調用超類型構造函數。可以通過使用 apply()
和 call()
方 法在新創建的對象上執行構造函數。關鍵代碼:Person.call(this,age,name)
缺點:無法復用,只能繼承父類的屬性
3)組合繼承
也叫偽經典繼承。指的是將原型鏈和借用構造函數的技術組合到一 起,從而發揮二者之長。使用原型鏈實現對原型屬性屬性和方法的繼承,通過借用構造函數來實現實例 屬性的繼承。
既通過在原型上定義方法實現了函數復用,又能保證每一個實例都有它自己的屬性。但是會有一個小bug,里面的age,name,有兩份,有一份的值為undefined,因為里面的apply()
和call()
方法會自動多調用一次。
4)寄生組合繼承
通過借用構造函數來繼承屬性,通過原型鏈的混成形式來繼承方法。 本質上,就是使用寄生式繼承來繼承超類型的原型,然后再將結果指定給子類型的原型。是公認繼承比較全面的一種方法,要寫全的話還是非常多的,我只會一個簡單的?,關鍵代碼:Star.prototype = Object.create(Person.prototype)
5)ES6的Class類繼承方式
可利用class關鍵字配合extends關鍵字來實現繼承。ES6中引入了class關鍵字來聲明類,而class(類)可通過extends
來繼承父類中屬性和方法,super
指向父類的原型對象,可以調用父類的屬性和方法,且子類constructor方法中必須有super關鍵字,且必須出現在this之前。
數據類型從大的方向來說分為兩種
基本數據類型:字符串(String),數字(Number),布爾(Boolean),空(Null),未定義(Undefined),Symbol(nbs)
復雜數據類型:對象(Object),數組(Array),函數(Function)
Symbol表示獨一無二的值,避免屬性名的沖突
typeof
檢測 存在的問題:null 或者數組打印出來也是 object
instanceof
(只能檢測復雜數據類型)
返回值是 true 或者 false
相關的構造函數只要在原型鏈上,就是 true,否則就是 false 可以用于檢測是不是數組
Object.prototype.toString.call
(要檢測的數據值)
為什么要借 Object.prototype.toString,因為自己的 toString 被自己原型重寫了,得不到類似[object Object]
var arr = [2, 3, 4] console.log(arr instanceof Array) console.log(Array.isArray(arr)) console.log(Object.prototype.toString.call(arr))
淺拷貝:只是拷貝一層,更深層次對象級別的只拷貝了地址
深拷貝:層層拷貝,每一級別的數據都會拷貝
淺拷貝方法:
1. 使用 lodash 淺拷貝 clone
方法,讓他們倆指向不同地址
2. 使用 Object.assign
方法
3. 使用es6語法的 ...
拓展運算符
深拷貝方法:
1. 使用JSON.parse(JSON.stringify(obj))
,缺點:當對象有方法和undefined屬性的時候會丟失
2. 使用遞歸
如果存在循環引用
就會出現堆棧溢出
解決思路:把處理好的對象存起來,在處理新的對象的時候,會現在這個存的地方找一找有沒有處理好,如果有就直接返回就行了
let obj = { name: "zs", age: 20, father: [2, 3, 4], }; function deepClone(target) { //這一行如果不用三元判斷 如果是數組會有bug會被拷貝成偽數組對象 let tempObj = Array.isArray(target) ? [] : {}; for (let key in target) { if (typeof target[key] === "object") { tempObj[key] = deepClone(target[key]); } else { tempObj[key] = target[key]; } } return tempObj; } let obj1 = deepClone(obj); console.log(obj1);
兩者都是數組刪除
的方法
1.splice改變原數組,slice不改變原數組。
2.slice會返回一個新的數組,可以用于截取數組
3.splice除了可以刪除之外,還可以替換,添加數組
4.splice可傳入3個參數,slice接受2個參數
兩者的作用都是截取字符串
的
substr是從起始索引號開始提取指定長度的字符串
substring是提取字符串中兩個指定索引號之間的字符
let和const都是用來聲明變量
的,在ES5中我們可以使用var來進行變量聲明
-使用let和const作用
- 防止for循環中變量提升的經典場景
- 不污染全局變量
var關鍵字聲明變量
1.var關鍵字聲明變量存在,變量提升
的問題;
2.var聲明的變量不存在塊級作用域
,如果是全局變量在任何地方都可以調用;
3.var聲明變量如果名稱重復了,后面聲明的會將前面聲明的覆蓋掉;
let關鍵子聲明變量
1.不存在變量提升
,let聲明變量不存在變量提升的問題:如果在let聲明變量前調用該變量就會報錯(提示初始化前無法訪問該變量);
2.塊級作用域
,let聲明變量存在塊級作用域(全局、函數、eval嚴格模式),只在當前的代碼塊中生效,如果在當前代碼塊以外調用就會報錯(當前的變量沒有定義);
3.不影響作用域鏈的操作
4.不允許變量重復聲明
,let聲明的變量是不允許重復聲明的,如果同一個名稱被重復聲明了就會報錯(當前的標識已經被聲明了);
const聲明變量
1.const聲明的變量也具有:不存在變量提升
、塊級作用域
、不允許重復聲明
的特點;
2.const聲明的變量都是常量
(不允許改變的量),一旦聲明就不允許被修改,如果修改就會報錯--常數變量賦值
3.一般第三方的框架中會大量使用const聲明變量,這樣可以避免用戶修改框架中的變量;
4.const實際上保證的,并不是變量的值不得改動,而是變量指向的那個內存地址所保存的數據不得改動。對于簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址
,因此等同于常量。
創建一個新的空對象。(即實例對象)
讓this指向這個新對象
執行構造函數里面的代碼,給這個新對象添加屬性和方法
返回這個新對象obj。(定義的構造函數中不寫返回值。)
防抖
防抖是指在事件觸發n秒后再執行,如果在n秒內再次被觸發,則重新計算時間。(就是在觸發某個事件后,在下一次觸發之前,中間的間隔時間如果超過設置的時間才會發送請求,一直觸發就不會發送請求
應用場景:
a、scroll事件滾動觸發,
b、搜索框輸入查詢
c、表單驗證
d、按鈕提交事件
e、瀏覽器窗口縮放,resize事件
function debounce(func, delay) { let timer = null // 計時器 return function (...args) { clearTimeout(timer) // 清除上一次計時器 timer = setTimeout(() => { // 重新定時 func.apply(this, args) }, delay) } }
節流
節流是指如果持續觸發某個事件,則每隔n秒執行一次。
function throtte(func, time) { let timer = null // 計時器 return function (...args) { if (timer) return // 無視,直接返回 timer = setTimeout(() => { func.apply(this, args) }, time) } }
這點簡單介紹概念,用法后面在詳細介紹
1) . 初始態pending
- pending。它的意思是 "待定的,將發生的",相當于是一個初始狀態。創建[Promise]對象時,且沒有調用resolve或者是reject方法,相當于是初始狀態。這個初始狀態會隨著你調用resolve,或者是reject函數而切換到另一種狀態。
2 ). 成功態resolved--
也叫fulfilled
- resolved。表示解決了,就是說這個承諾實現了。 要實現從pending到resolved的轉變,需要在 創建Promise對象時,在函數體中調用了resolve方法(即第一個參數)。
3) . 失敗態rejected
- rejected。拒絕,失敗。表示這個承諾沒有做到,失敗了。要實現從pending到rejected的轉換,只需要在創建Promise對象時,調用reject函數。
// 上口訣 雙層for循環 外層長度-1 內層長度-1-i let arr = [4, 3, 1, 7, 8, 10] for (let i = 0; i < arr.length - 1; i++) { for (let j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1]) { let temp = arr[j] arr[j] = arr[j + 1] arr[j + 1] = temp } } } console.log(arr)
MVVM
是三個單詞的縮寫,model
(數據,一般來自ajax或本地存儲)+view
(視圖template)+viewmodel(vue實例)
model數據變了,視圖會跟著改變,如果用的是v-model,數據也會跟著改變,viewmodel在中間起一個橋梁作用
model 和 view 就像現實中房東和租客一樣,他們是不認識的,通過中介 viewmodel好處
:
由于 model 和 view 是沒有關系的,是通過 viewmodel 結合在一起的,所以維護起來很方便,因為 model 邏輯代買改了,view 不用改
因為數據變了。視圖也會跟著變,所以在 vue 中不用操作dom來改變視圖
數據驅動
解耦(降低了耦合性
)
vue中的生命周期是指組件從創建到銷毀的過程,主要分為4個周期8個鉤子函數
1.分別是創建階段的beforeCreate
,created
,一般在beforeCreate寫loading加載效果,使用戶體驗更好,一般在created中發送ajax請求獲取數據
2.然后是掛載階段的beforeMount
,mounted
,一般會在mounted中操作DOM元素
3.更新階段的是beforeUpdate
,updated
,當數據更新時需要做統一的業務處理時,拿到最新的dom,可以使用updated 這個鉤子函數
4.最后是銷毀階段的beforeDestroy
,destroyed
,可以在beforeDestroy做一些清理的工作,比如說定時器 和解綁一些addEventListener監聽的事件
補充:(還有keep-alive
的兩個鉤子函數,使用場景是當組件切換時會進行銷毀,因此組件中的初始化的4個鉤子函數會多次執行,比較浪費資源,此時可以使用keep-alive紀行組件的緩存,可以讓組件切換時不被銷毀,keep-alive有兩個獨有的鉤子函數,分別是activated
和deactivated
,是組件激活和失活時會執行的兩個鉤子函數)
單向數據流是指父組件向子組件傳遞數據,子組件通過props
接收,當父組件中的值改變了,子組件中對應的數據也會改變,因為props是只讀
的,所以無法直接在子組件中對父組件傳遞過來的值進行修改,但是如果這個數據是一個引用數據類型,是可以直接在子組件中修改數據中的某個屬性的,只要不改變這個數據的內存地址
就可以
數據 -> 視圖
視圖 -> 數據
vue中普通指令都可以實現數據變了,視圖會跟著變,但是有一個特殊的指令叫v-model
,它一般用于表單控件,它可以實現雙向數據綁定,所謂的雙向數據就是數據變了,視圖就會跟著改變,反過來也是
v-model
一般配合input
框使用,實現雙向數據綁定的效果,它是v-bind
和v-on
的語法糖,原理是通過v-bind將數據綁定給input框,再通過v-on:input
,在input中的值改變時,通過$event可以獲取到事件源對象 再通過target.value
獲取到input中更新后的值 將這個值再賦值給綁定的數據即可
在vue的組件使用自定義事件時,$event代表子組件拋出的數據,當這個自定義事件觸發一個方法時, 可以不傳$event而且可以在方法中進行接收,但是如果寫的話就一定要寫成$event的形式,這是一個固定寫法, 或者這個方法既要傳參又要使用事件對象,這個時候$event也是必須要寫的 - @click='fn' 在回調函數直接通過參數可以拿到事件對象 - @click='fn($event)' 這個時候@event是固定寫法
1.初始化階段時,先執行父組件的beforeCreate
、created
、beforeMount
三個鉤子函數,然后執行子組件的beforeCreate
、created
、beforeMount
、mounted
四個鉤子函數,最后執行父組件的mounted鉤子函數
2.更新階段,先執行父組件的beforeUpdate
,然后執行子組件的beforeUpdate
,updated
,最后執行父組件的updated
3.銷毀階段,先執行父組件的beforeDestroy
,然后執行子組件的eforeDestroy
,destroyed
,最后執行父組件的destroyed
v-if
和v-show
都可以控制標簽,實現組件的顯示與隱藏,不同點是v-show是通過display
的block和none
屬性來控制的,當元素隱藏時,頁面結構依然存在
v-if是通過將元素創建和銷毀來控制顯示與隱藏的,當v-if的條件為否時,會直接銷毀該元素,當滿足時會重新創建出來,有可能會影響頁面的回流或重繪
如果該元素需要頻繁切換時可以使用v-show,不需要頻繁切換時可以使用v-if,提高性能
因為v-for的優先級比v-if要高,兩者同時作用于一個標簽或組件時,v-for會優先執行,執行后再進行v-if的判斷,但是不滿足v-if的條件的時候是可以不執行v-for的,這時候就會造成資源浪費,性能比較差
解決辦法是可以通過計算屬性將滿足v-if判斷條件的數據篩選出來,再使用v-if直接渲染篩選后的數據,或者是當v-if不依賴v-for時,可以通過template
將v-if寫在循環的外部,這樣當不滿足v-if的判斷條件時,就不會再執行v-for了,也可以將數據放在計算屬性
里面計算過濾出來的數據在交給v-for循環,代替v-if的作用,即可解決。
應用場景
v-imgerror
公司項目中有的用戶頭像可能加載報錯,可以給他一張默認圖片, onerror this.img=默認圖片
v-focus
打開帶有搜索的頁面的時候,實現自動把光標定位到 input 中
自定義指令的鉤子函數
1.bind
屬性綁定的時候執行 只會有一次
2. inserted
當前指令所在的元素插入到頁面中的時候執行一次
3. update
當前指令所在的組件中的 data 數據有更新就會執行,可以執行多次
// 指令的鉤子有三個 bind inserted update // bind inserted 只會執行一次 // update 會反復執行 Vue.directive('focus', { inserted(el) { el.focus() }, }) Vue.directive('red', { bind(el) { el.style.color = 'red' }, }) Vue.directive('check', { update(el) { const reg = /^[a-zA-Z0-9]+$/ if (reg.test(el.value)) { el.style.color = 'green' } else { el.style.color = 'red' } }, })
這塊部分理解不是很透徹,大家淺看一下就可以了?
概念:瀏覽器會將請求后的資源進行存貯為離線資源,當下次需要該資源時,瀏覽器會根據緩存機制決定直接使用緩存資源還是再次向服務器發送請求
作用:
減少了不必要數據的傳輸、降低服務器的壓力
加快了客戶端訪問速度
增強用戶體驗
強緩存:過期之前一直用本地離線資源 不會和服務器交互
http1.0 expire 具體的時間2023年1月1日
http1.1 cache-control 時間期限1年 (優先級高)
協商緩存 本質是看本地東西和服務器有沒有變舊(服務器上有沒有更新的資源) 強緩存不會和服務器交互 協商緩存會交互一次來判斷東西有沒有變舊
http1.0 last-modified/if-modified-since
http1.1 etag/if-none-match(優先級高)
當前頁面中有一個img,它的src是logo.png
1. 先看本地有沒有緩存資源,如果沒有,就需要向服務器發請求 拿回來這個資源同時拿回來expire
,cache-control
,last-modified
,etag
(響應報文中)
2. 過了一段時間(不確定的),又有一個別的頁面上面有一個img,src也是logo.png,這個時候就去看一下本地有沒有緩存資源,發現有,再看一下它expire
,catch-control
(如果有,優先級是看cache-control
),如果沒有過期,就用就行了(這塊屬于強緩存) 但是發現如果過期了,就開始進入協商緩存的階段,就向服務器發送一個請求把if-modified-since
(值就是last-modifyed
)/if-none-match(etag)
通過請求頭發過去, 服務器開始對比看看服務器上的資源有沒有比本地更新一點,如果服務器資源還是舊的,返回一個狀態碼叫304,瀏覽器一看狀態是304就繼續用本地離線資源,如果服務器資源有更新的資源,狀態碼就是200,服務器就需要傳給瀏覽器一個新的logo.png,流程重新再走一遍
本人技術棧是主要是前端vue的,所以對這方面的知識還是有所欠缺的,盡量說的明白一點,其實我也不是很懂,大致明白,如果想要全面理解透還是需要很多技術儲備的,很明顯我不是的哈哈?
觀察者模式即一個對象被多個對象所依賴,當被依賴的對象發生更新時,會自動通知所有依賴的對象
觀察者模式定義了對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都將得到通知,并自動更新
比喻:
寶寶 -> 父母爺爺奶奶 一對多的依賴關系
寶寶哭 -> 父母爺爺奶奶趕緊過來服務 當一個對象的狀態發生改變時,所有依賴于它的對象都將得到通知,并自動更新
模式特點: 有二個主體
一個是被觀察者 Dep
一個是觀察者 watcher
,在vue中v-band
就是采用這種模式理念,缺點是耦合性太高
發布-訂閱模式其實是一種對象間一對多的依賴關系,當一個對象的狀態發送改變時,所有依賴于它的對象都將得到狀態改變的通知。
在現在的發布訂閱模式中,稱為發布者的消息發送者不會將消息直接發送給訂閱者,這意味著發布者和訂閱者不知道彼此的存在。在發布者和訂閱者之間存在第三個組件,稱為調度中心或事件通道(event bus),它維持著發布者和訂閱者之間的聯系,過濾所有發布者傳入的消息并相應地分發它們給訂閱者
模式特點:有三個主體
發布者 調度中心 訂閱者,在vue中eventBus
體現出來了這種模式理念,可以實現解耦
主體數量不一樣,觀察者模式有二個主體 分別是被觀察者 Dep
和觀察者 watcher
,發布訂閱模式有三個主體 分別是發布者 調度中心(事件通道 ) 訂閱者
發布訂閱模式相比觀察者模式多了個事件通道,事件通道作為調度中心,管理事件的訂閱和發布工作,徹底隔絕了訂閱者和發布者的依賴關系,訂閱者和發布者是解耦的(不知道彼此存在)
到此,關于“web前端常見面試題實例分析”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。