釋出文章主要也是鞏固自己的知識更加熟練,全憑自己的理解和網上查資料總結出來的,如有不對的地方還望多多指點。下面是我總結的一下常見面試題,為了督促自己還可以會繼續更新
在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之前。
資料型別從大的方向來說分為兩種
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。(定義的建構函式中不寫返回值。)
防抖
function debounce(func, delay) { let timer = null // 計時器 return function (...args) { clearTimeout(timer) // 清除上一次計時器 timer = setTimeout(() => { // 重新定時 func.apply(this, args) }, delay) } }
節流
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範例)
好處
:降低了耦合性
)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,提高效能
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' } }, })
這塊部分理解不是很透徹,大家淺看一下就可以了?
expire
,cache-control
,last-modified
,etag
(響應報文中)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
,釋出訂閱模式有三個主體 分別是釋出者 排程中心(事件通道 ) 訂閱者
釋出訂閱模式相比觀察者模式多了個事件通道,事件通道作為排程中心,管理事件的訂閱和釋出工作,徹底隔絕了訂閱者和釋出者的依賴關係,訂閱者和釋出者是解耦的(不知道彼此存在)
(學習視訊分享:、jQuery視訊教學)
以上就是總結一些前端常見面試題(附答案),帶你鞏固知識點!的詳細內容,更多請關注TW511.COM其它相關文章!