接著昨天的前端面試題總結(jié)寫的哈,有在找工作的伙伴,建議仔細(xì)閱讀!
10.什么是原型鏈原型:每個javascript創(chuàng)建的時候都會關(guān)聯(lián)另一個對象,這個對象就是原型,對象會從原型繼承屬性構(gòu)造函數(shù)可以通過prototype去尋找他關(guān)聯(lián)的原型,A.prototype就是它關(guān)聯(lián)的原型對象,原型對象可以通過構(gòu)造器constructor來尋找與自身關(guān)聯(lián)的構(gòu)造函數(shù)
function A () {
}
A.prototype.constructor === A //true
原型鏈:原型鏈?zhǔn)怯稍蛯ο蠼M成,每個對象都有proto屬性,指向該構(gòu)造函數(shù)的原型,proto將對象連接起來組成了原型鏈原型鏈查找機制:當(dāng)查找對象的屬性時,如果實例對象不存在該屬性,沿著原型鏈向上一級查找,直到找到object.prototype(也就是對象原型object.prototype為null),停止查找到返回undefined
function A () {
}
new A().__proto__ === A.prototype //true
原型上的屬性和方法被實例共享
function A () {
}
A.prototype.name = 'a'
var a = new A()
var b = new A()
a.name === b.name // true
a.__proto__.name === b.__proto__.name // true
instanceOf原理:instamceOf可以判斷實例對象的proto屬性與構(gòu)造函數(shù)的prototype是不是同一地址(如果網(wǎng)頁中有多個全局環(huán)境就會不準(zhǔn)確)
function _instanceOf(obj, type) {
var obj = obj.__proto__
var type = type.prototype
while(true) {
if (obj == null) {
return false
}
if (obj == type) {
return true
}
obj = obj.__proto__
}
}
var a = [1, 2, 3]
_instanceOf(a, Array)
11.深拷貝和淺拷貝淺拷貝只是復(fù)制引用,新舊對象共享一塊內(nèi)存,一般把第一層拷貝到一個對象上,改變其中一個另一個也會改變
var obj = {
name: 'a',
age: 18,
arr: [1, 2]
}
function shallowCopy(obj) {
var newObj = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) { // 過濾掉原型上的屬性
newObj[prop] = obj[prop];
}
}
return newObj;
}
var obj1 = shallowCopy(obj)
var obj2 = obj
obj1.name = 'b'
obj2.age = 20
obj2.arr[0] = 3
obj1.arr[0] = 4
console.log(obj) // {name: "a", age: 20, arr: [4, 2]}
console.log(obj1) // {name: "b", age: 18, arr: [4, 2]}
console.log(obj2) // {name: "a", age: 20, arr: [4, 2]}
我們通過淺拷貝得到obj1,改變obj1的name,obj不會發(fā)生改變,通過賦值得到obj2,obj2改變age值obj的值也會被改變。說明賦值得到的對象只是改變了指針,淺拷貝是創(chuàng)建了新對象。
我們通過obj2和obj1都改變的值,發(fā)現(xiàn)obj,ob1,obj2都發(fā)生了改變,所以無論是淺拷貝還是賦值都會改變原始數(shù)據(jù)(淺拷貝只拷貝了一層對象的屬性)
深拷貝:復(fù)制并創(chuàng)建一個一摸一樣的對象(遞歸復(fù)制了所有層級),不共享內(nèi)存,改變其中一個另一個不會改變
var obj = {
name: 'a',
age: 18,
arr: [1, 2]
}
function copy (obj) {
var newobj = Array.isArray(obj) ? [] : {};
if(typeof obj !== 'object'){
return;
}
for(var i in obj){
if (obj.hasOwnProperty(i)) {
newobj[i] = typeof obj[i] === 'object' ? copy(obj[i]) : obj[i];
}
}
return newobj
}
var copyObj = copy(obj)
copyObj.arr[0] = 3
console.log(copyObj) //{name: "a", age: 20, arr: [3, 2]}
console.log(obj) //{name: "a", age: 20, arr: [1, 2]}
12.實現(xiàn)繼承原型鏈繼承(在實例化一個類時,新創(chuàng)建的對象復(fù)制了父類構(gòu)造函數(shù)的屬性和方法,并將proto指向父類的原型對象,當(dāng)在子類上找不到對應(yīng)的屬性和方法時,將會在父類實例上去找。)
function Big () {
this.age = [1, 2, 3]
}
Big.prototype.getAge = function () {
return this.age
}
function Small() {}
Small.prototype = new Big()
var small = new Small()
console.log(small.age) // [1, 2, 3]
console.log(small.getAge()) // [1, 2, 3]
缺點1:引用缺陷(修改其中一個Small實例的父類變量會影響所有繼承Big的實例)
small.age[0] = 12
var small1 = new Small()
console.log(small1.age) // [12, 2, 3]
console.log(small.age) // [12, 2, 3]
缺點2:無法為不同的實例初始化繼承來的屬性
function Big (name) {
this.age = [1, 2, 3]
this.name = name
}
Big.prototype.getAge = function () {
return this.age
}
function Small() {}
Small.prototype = new Big('small')
var small = new Small()
var small1 = new Small()
console.log(small1.name) // small
console.log(small.name) // small
構(gòu)造函數(shù)繼承(在子類的構(gòu)造函數(shù)中執(zhí)行父類的構(gòu)造函數(shù),并為其綁定子類的this,讓父類的構(gòu)造函數(shù)把成員屬性和方法都掛到子類的this上)
function Big (name) {
this.age = [1, 2, 3]
this.name = name
}
Big.prototype.getAge = function () {
return this.age
}
function Small(name) {
Big.apply(this, arguments)
}
var small = new Small('small')
var small1 = new Small('small1')
console.log(small.name) // small
console.log(small1.name) // small1
small.age[0] = 12
console.log(small.age) // [12, 2, 3]
console.log(small1.age) // [1, 2, 3]
缺點:無法訪問原型上的方法
small.getAge() //small.getAge is not a function組合式繼承(將原型鏈繼承和構(gòu)造函數(shù)繼承組合到一起, 綜合了原型鏈繼承和構(gòu)造函數(shù)繼承的優(yōu)點)
function Big (name) {
this.age = [1, 2, 3]
this.name = name
}
Big.prototype.getAge = function () {
return this.age
}
function Small(name) {
Big.apply(this, arguments)
}
Small.prototype = new Big()
var small = new Small('small')
var small1 = new Small('small1')
console.log(small.name) // small
console.log(small1.name) // small1
small.age[0] = 12
console.log(small.age) // [12, 2, 3]
console.log(small1.age) // [1, 2, 3]
console.log(small.getAge()) // [12, 2, 3]
console.log(small1.getAge()) // [1, 2, 3]
小缺點:調(diào)用了兩次父類構(gòu)造函數(shù)
寄生組合式繼承(在組合繼承的基礎(chǔ)上減少一次多余的調(diào)用父類構(gòu)造函數(shù))
function Big (name) {
this.age = [1, 2, 3]
this.name = name
}
Big.prototype.getAge = function () {
return this.age
}
function Small(name) {
Big.apply(this, arguments)
}
// 對父類原型進(jìn)行拷貝,否則子類原型和父類原型指向同一個對象,修改子類原型會影響父類
Small.prototype = Object.create(Big.prototype)
var small = new Small('small')
var small1 = new Small('small1')
console.log(small.name) // small
console.log(small1.name) // small1
small.age[0] = 12
console.log(small.age) // [12, 2, 3]
console.log(small1.age) // [1, 2, 3]
console.log(small.getAge()) // [12, 2, 3]
console.log(small1.getAge()) // [1, 2, 3]
注意:對父類原型進(jìn)行拷貝后賦值給子類原型,因此Small上的constructor屬性被重寫,需要修復(fù)Small.prototype.constructor = Dog;
extends繼承(class和extends是es6新增的,class創(chuàng)建一個類,extends實現(xiàn)繼承)
class Big {
constructor(age) {
this.age = age;
}
getAge () {
return this.age
}
}
class Small extends Big {
constructor(age) {
super(age)
}
}
var small = new Small([1, 2, 3])
var small1 = new Small([12, 2, 3])
small.age[0] = 13
console.log(small.age) // [13, 2, 3]
console.log(small.getAge()) // [13, 2, 3]
console.log(small1.age) // [12, 2, 3]
console.log(small1.getAge()) // [12, 2, 3]
瀏覽器網(wǎng)絡(luò)1.常用http狀態(tài)碼200 成功狀態(tài)碼301 永久重定向,302 臨時重定向400 請求語法錯誤, 401 請求需要http認(rèn)證,403 不允許訪問資源,404 資源未找到500 服務(wù)器內(nèi)部錯誤,502 訪問時出錯,503 服務(wù)器忙,無法響應(yīng)
2.https原理http協(xié)議:客戶端瀏覽器與web服務(wù)器之間的應(yīng)用層通訊協(xié)議https協(xié)議:HTTP+SSL/TLS,http下加入SSL層,https安全基礎(chǔ)時SSL,用于安全的HTTP數(shù)據(jù)傳輸https優(yōu)勢:內(nèi)容經(jīng)過對稱加密,每個連接會生成唯一的加密密鑰,內(nèi)容經(jīng)過完整性校驗,第三方無法偽造身份使用對稱加密(加密和解密使用的是同一個密鑰)被中間人攔截,中間人可以獲取密鑰,就可以對傳輸?shù)男畔⑦M(jìn)行窺視和篡改使用非對稱密鑰(雙方必須協(xié)商一對密鑰,一個私鑰和一個公鑰)用私鑰加密的數(shù)據(jù),只有對應(yīng)的公鑰才能解密,用公鑰加密的數(shù)據(jù),只有對應(yīng)的私鑰才能解密,弊端:RSA算法很慢非對稱密鑰+對稱密鑰(結(jié)合兩者優(yōu)點)客戶端獲取公鑰確認(rèn)服務(wù)器身份通過SSL證書,客戶端接受到服務(wù)端發(fā)來的SSL證書給客戶端。
3.前端安全XSS攻擊:注入惡意代碼來攻擊。攻擊者在目標(biāo)網(wǎng)站上注入惡意代碼,被攻擊者登陸網(wǎng)站執(zhí)行這些惡意代碼,這些腳本可以讀取 cookie,session tokens,或者其它敏感的網(wǎng)站信息,對用戶進(jìn)行釣魚欺詐(打開新標(biāo)簽跳轉(zhuǎn),新標(biāo)簽存在惡意代碼,跳轉(zhuǎn)到偽造的頁面),網(wǎng)頁植入廣告等。XSS攻擊防御手段:禁止JavaScript讀取某些敏感cookie,限制輸入內(nèi)容和長度控制,檢測是否有惡意代碼注入CSRF攻擊:誘導(dǎo)用戶進(jìn)入第三方,獲取到登錄憑證,冒充用戶對被攻擊的站點執(zhí)行操作,導(dǎo)致賬號被劫持防御CSRF攻擊:驗證token(請求服務(wù)器時,返回token,每個請求需要加上token),
5.瀏覽器緩存瀏覽器每次發(fā)起請求,都會在瀏覽器緩存中查找請求結(jié)果和緩存標(biāo)識,瀏覽器每次拿到的數(shù)據(jù)會將結(jié)果和標(biāo)識存入瀏覽器中強制緩存:當(dāng)瀏覽器向服務(wù)器發(fā)起請求時,服務(wù)器會將緩存規(guī)則放入HTTP響應(yīng)報文的HTTP頭中和請求結(jié)果一起返回給瀏覽器,控制強制緩存的字段分別是Expires和Cache-Control,其中Cache-Control優(yōu)先級比Expires高。協(xié)商緩存:強制緩存失效后,瀏覽器攜帶緩存標(biāo)識向服務(wù)器發(fā)起請求,由服務(wù)器根據(jù)緩存標(biāo)識決定是否使用緩存的過程。(協(xié)商緩存生效,服務(wù)器返回304,資源未更新,協(xié)商緩存失效,服務(wù)器返回200,資源更新重新緩存)詳情可以看這篇文章徹底理解瀏覽器的緩存機制
框架1.什么是vue生命周期每個vue實例在被創(chuàng)建之前都要經(jīng)過一系列初始化過程,這個過程就是vue生命周期。(開始創(chuàng)建、初始化數(shù)據(jù)、編譯模板、掛載Dom→渲染、更新→渲染、卸載等一系列過程)beforeCreate: 完成實例初始化,this指向被創(chuàng)建的實例,data,computed,watch,mothods方法和數(shù)據(jù)都不可以訪問created: 實例創(chuàng)建完成,data,computed,watch,methods可被訪問,未掛載dom,可對data進(jìn)行操作,操作dom需放到nextTick中beforeMount: 有了el,找到對應(yīng)的template編譯成render函數(shù)mounted: 完成掛載dom和渲染,可以對dom進(jìn)行操作,并獲取到dom節(jié)點,可以發(fā)起后端請求拿到數(shù)據(jù)beforeUpdate: 數(shù)據(jù)更新之前訪問現(xiàn)有dom,可以手動移除已添加事件的監(jiān)聽updated: 組件dom已完成更新,可執(zhí)行依賴的dom 操作,不要操作數(shù)據(jù)會陷入死循環(huán)activated: keep-alive緩存組件激活時調(diào)用deactivated keep-alive移除時調(diào)用beforeDestroy: 實例銷毀之前調(diào)用,可以銷毀定時器destroyed: 組件已經(jīng)被銷毀
2.第一次頁面加載會觸發(fā)哪幾個鉤子會觸發(fā)beforeCreate, created, beforeMount, mounted
3.created和mounted的區(qū)別created:在模板渲染成html前調(diào)用,即通常初始化某些屬性值,然后再渲染成視圖。mounted:在模板渲染成html后調(diào)用,通常是初始化頁面完成后,再對html的dom節(jié)點進(jìn)行一些需要的操作。
4.hash模式和history模式在vue的路由配置中有mode選項 最直觀的區(qū)別就是在url中 hash 帶了一個很丑的 # 而history是沒有#的。hash 雖然出現(xiàn)在 URL 中,但不會被包括在 HTTP 請求中,對后端完全沒有影響,因此改變 hash 不會重新加載頁面。history利用了HTML5中新增的 pushState() 和 replaceState() 方法。這兩個方法應(yīng)用于瀏覽器的歷史記錄棧,在當(dāng)前已有的 back、forward、go 的基礎(chǔ)之上,它們提供了對歷史記錄進(jìn)行修改的功能。只是當(dāng)它們執(zhí)行修改時,雖然改變了當(dāng)前的 URL,但瀏覽器不會立即向后端發(fā)送請求。history模式需要后臺配置支持
5.computed和watch區(qū)別computed: 依賴的屬性值發(fā)生改變才會重新計算,得出最后的值watch: 當(dāng)依賴的data的數(shù)據(jù)變化,執(zhí)行回調(diào)(可以觀察數(shù)據(jù)的某些變化,來做一些事情)
6.vue中key的作用key是給每一個vnode的唯一id,可以依靠key,更準(zhǔn)確, 更快的拿到oldVnode中對應(yīng)的vnode節(jié)點。
7.vue的兩個核心點數(shù)據(jù)驅(qū)動:ViewModel,保證視圖的一致性組件系統(tǒng):組件化,封裝可復(fù)用的組件,頁面上每個獨立的區(qū)域都可以看成一個組件,組件可以自由組合成頁面
8.SPA首屏加載慢如何解決使用路由懶加載使用SSR渲染優(yōu)化webpack打包體積圖片使用CDN加速
9.vue禁止彈窗后的屏幕滾動主要是是寫一個點擊出現(xiàn)彈窗禁止屏幕滾動的方法,關(guān)閉彈窗屏幕可以正常滾動
methods : {
//禁止?jié)L動
stop(){
var mo=function(e){e.preventDefault();};
document.body.style.overflow='hidden';
document.addEventListener("touchmove",mo,false);//禁止頁面滑動
},
/取消滑動限制/
move(){
var mo=function(e){e.preventDefault();};
document.body.style.overflow='';//出現(xiàn)滾動條
document.removeEventListener("touchmove",mo,false);
}
}
10.Vuex中actions和mutations的區(qū)別action主要處理的是異步的操作,mutation必須同步執(zhí)行,而action就不受這樣的限制,也就是說action中我們既可以處理同步,也可以處理異步的操作action改變狀態(tài),最后是通過提交mutation
如果有錯誤或者不嚴(yán)謹(jǐn)?shù)牡胤?,請?wù)必給予指正,十分感謝。