-
HTTP報(bào)文結(jié)構(gòu)?
HTTP報(bào)文結(jié)構(gòu) - ** HTTP緩存**
緩存機(jī)制 -
常見網(wǎng)絡(luò)安全漏洞
常見網(wǎng)絡(luò)安全漏洞 -
如何進(jìn)行數(shù)組扁平化處理?
將一個(gè)多維數(shù)組變?yōu)橐粋€(gè)一維數(shù)組
方法1:遞歸
const arr = [1,2,[2,3],[5,6],7,0]
const fn = (arr, newArr) => {
arr.forEach(item => {
if(Array.isArray(item)) {
fn(item, newArr)
} else {
newArr.push(item)
}
})
return newArr
}
console.log(fn(arr, [])) // [1, 2, 2, 3, 5, 6, 7, 0]
方法2:flat()
flat()接受一個(gè)數(shù)值參數(shù),表示需要拉平的層級(jí),Infinity表示無限層級(jí)的拉平。
[1, 2, [3, [4, 5]]].flat() // [1, 2, 3, [4, 5]]
[1, 2, [3, [4, 5]]].flat(2) // [1, 2, 3, 4, 5]
arr.flat(Infinity) // [1, 2, 2, 3, 5, 6, 7, 0]
方法3:reduce() 函數(shù):遍歷數(shù)組,每次返回上一次的處理后的值。reduce(function(prev,next){}, initVal), initVal 為prev的初始值,不傳initVal,prev的初始值為數(shù)組的第一個(gè)元素,next為第二個(gè)數(shù)組元素。
// reduce 每次的prev都是[],所以采用數(shù)組的concat()
const fn2 = arr => {
return arr.reduce((prev,next) => {
return prev.concat(Array.isArray(next) ? fn2(next) : next)
},[])
}
-
防抖debounce
觸發(fā)高頻事件后n秒內(nèi)會(huì)執(zhí)行一次,如果n秒內(nèi)再次觸發(fā),則重新計(jì)算時(shí)間進(jìn)行執(zhí)行。
即:觸發(fā)高頻事件每隔一定時(shí)間執(zhí)行一次。
場景:防抖常應(yīng)用于用戶進(jìn)行搜索輸入節(jié)約請求資源,滾動(dòng)事件等
const debounce = (fn,time = 500) => {
let timer = 0
return function() {
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this)
}, time)
}
}
// 高頻觸發(fā)函數(shù)mousemove
const box = document.getElementsByClassName('box')[0]
const fn4 = () => console.log('觸發(fā)函數(shù)')
box.addEventListener('mousemove', debounce(fn4))
-
節(jié)流throttle
n秒內(nèi)觸發(fā)高頻事件只會(huì)執(zhí)行一次, 所以節(jié)流會(huì)稀釋函數(shù)的執(zhí)行頻率。
場景:節(jié)流常應(yīng)用于防重復(fù)點(diǎn)擊。
const throttle = (fn, time = 100) => {
let isFinished = false
return function() {
if(isFinished) {
clearTimeout(timer)
return
}
timer = setTimeout(() => {
fn.apply(this)
isFinished = true
}, time)
}
}
// 防重復(fù)點(diǎn)擊
const box = document.getElementsByClassName('box')[0]
const fn4 = () => console.log('觸發(fā)函數(shù)')
box.addEventListener('click', throttle(fn4))
-
arguments.callee
在函數(shù)內(nèi)部,有兩個(gè)特殊的對象:arguments 和 this。其中, arguments 的主要用途是保存函數(shù)參數(shù), 但這個(gè)對象還有一個(gè)名叫 callee 的屬性,該屬性是一個(gè)指針,指向擁有這個(gè) arguments 對象的函數(shù)。
場景:使用遞歸的過程中會(huì)根據(jù)條件來調(diào)用函數(shù)本身,這樣會(huì)導(dǎo)致一個(gè)問題,函數(shù)內(nèi)部存在一個(gè)我們自定義的函數(shù)名,不利于再次封裝。
// 使用函數(shù)名
const fn = function(num) {
if(num > 1) {
return num * fn(num - 1)
} else {
return 1
}
}
// 使用arguments.callee
const fn = function(num) {
if(num > 1) {
return num * arguments.callee(num - 1)
} else {
return 1
}
}
-
函數(shù)珂里化
指的是將一個(gè)接受多個(gè)參數(shù)的函數(shù)變?yōu)榻邮芤粋€(gè)參數(shù),返回一個(gè)函數(shù)的固定形式,便于再次調(diào)用。
// 求和:curry(1)(2)(3)(4) 及curry(2)(2,3,4)(5)
const curry = function() {
const _arg = [...arguments]
const fn = function() {
_arg.push(...arguments)
return fn
}
fn.toString = () => _arg.reduce((prev, next) => prev + next)
return fn
}
-
原型(prototype)、原型鏈和原型繼承
image.png
- 所有引用類型(函數(shù),數(shù)組,對象)都擁有proto屬性(隱式原型)
- 所有函數(shù)擁有prototype屬性(顯式原型)(僅限函數(shù))
- 原型鏈的實(shí)現(xiàn):查找屬性,如果本身沒有,則會(huì)去__ proto __ 中查找,也就是構(gòu)造函數(shù)的顯式原型中查找,如果構(gòu)造函數(shù)中也沒有該屬性,因?yàn)闃?gòu)造函數(shù)也是對象,也有 __ proto __,那么會(huì)去它的顯式原型中查找,一直到null,如果沒有則返回undefined。
-
構(gòu)造函數(shù)都有一個(gè)prototype屬性指向原型對象,原型對象通過constructor屬性指向構(gòu)造函數(shù)本身。
實(shí)例對象都有一個(gè)__ proto __屬性指向原型對象 - 實(shí)例對象的__ proto __指向構(gòu)造函數(shù)的prototype,從而實(shí)現(xiàn)繼承。
prototype對象相當(dāng)于特定類型所有實(shí)例對象都可以訪問的公共容器 - 繼承:
(1)原型鏈繼承
(2)call和apply。區(qū)別call(this,p1,p2,p3,...),apply(this.[...params])第二個(gè)開始為參數(shù)集合
(3)方法繼承:深度拷貝原型,然后更改constructor屬性
person._ proto _ = Object.create(People.prototype)
peson.constructor = Person
或者
Person.prototype = Object.create(People.prototype)
peson.constructor = Person
https://blog.csdn.net/yucihent/article/details/79424506
https://zhuanlan.zhihu.com/p/35790971
- new 操作符的實(shí)現(xiàn)
思路:新創(chuàng)建一個(gè)空對象,新對象原型賦值構(gòu)造函數(shù)的原型,執(zhí)行構(gòu)造函數(shù)并綁定this到新對象。(新對象擁有構(gòu)造函數(shù)及原型上的屬性和方法)
function _MyNew(obj) {
// 創(chuàng)建一個(gè)空對象
let newObj = Object.create()
// 設(shè)置空對象的原型
newObj.__proto__ = obj.prototype
// 使用apply綁定this,執(zhí)行構(gòu)造函數(shù)
const res = obj.apply(newObj)
const isObject = typeof res === 'object' && res !== null;
const isFunction = typeof res === 'function';
return isObject || isFunction ? res : obj;
}
-
宏任務(wù)與微任務(wù)
Javascript 是單線程腳本語言。分為同步任務(wù)(立即執(zhí)行)、異步任務(wù)(不會(huì)立即執(zhí)行),異步任務(wù)分為宏任務(wù)、微任務(wù),異步任務(wù)進(jìn)過事件注冊模塊將回調(diào)添加到任務(wù)隊(duì)列進(jìn)行處理。
(1)宏任務(wù)
常見的有:
setTimeout
setInterval
requireAnimationFrame請求動(dòng)畫幀(瀏覽器獨(dú)有)
UI render(瀏覽器獨(dú)有)
setImmediate(node獨(dú)有)
I/O
(2)微任務(wù)
常見的有:
Promise.then()
Process.nextTick(node獨(dú)有)
Object.observe
MutationObserve
(1)當(dāng)一個(gè)異步任務(wù)進(jìn)入棧的時(shí)候,主線程會(huì)判斷是同步還是異步任務(wù),如果是同步任務(wù),則立即執(zhí)行;如果是異步任務(wù),則將該任務(wù)交給異步處理模塊處理,當(dāng)異步處理完到觸發(fā)條件的時(shí)候,根據(jù)任務(wù)的類型,將回調(diào)壓入隊(duì)列之中。如果是宏任務(wù),則新增一個(gè)宏任務(wù),任務(wù)隊(duì)列中的宏任務(wù)可以有多個(gè);如果是微任務(wù),則直接壓入微任務(wù)隊(duì)列。
(2)當(dāng)兩個(gè)宏任務(wù)隊(duì)列的時(shí)候,第一個(gè)宏任務(wù)隊(duì)列中有一個(gè)微任務(wù):即當(dāng)在執(zhí)行宏任務(wù)的時(shí)候,遇到微任務(wù)則將微任務(wù)加入微任務(wù)隊(duì)列,最后剩下一個(gè)微任務(wù)和一個(gè)宏任務(wù),此時(shí)會(huì)先執(zhí)行微任務(wù),再執(zhí)行宏任務(wù)。
(3)宏任務(wù)與微任務(wù)在瀏覽器和node中的執(zhí)行有所差異
瀏覽器:執(zhí)行宏任務(wù),然后執(zhí)行宏任務(wù)對應(yīng)的微任務(wù),重復(fù)進(jìn)行。由于執(zhí)行棧的入口為script,而全局任務(wù)為宏任務(wù),所以當(dāng)棧為空的時(shí)候,同步任務(wù)執(zhí)行完畢,會(huì)先執(zhí)行微任務(wù)隊(duì)列。微任務(wù)執(zhí)行完畢,會(huì)讀取宏任務(wù)隊(duì)列中最前的任務(wù),執(zhí)行宏任務(wù)的過程中,如果遇到微任務(wù),則依次加入微任務(wù)隊(duì)列,??蘸?,再次讀取微任務(wù),依次類推。
node:執(zhí)行完全部的宏任務(wù),然后執(zhí)行微任務(wù)。
console.log('1')
setTimeout(()=>{
console.log('2');
new Promise(resolve=>{
console.log('3')
resolve();
}).then(()=>{
console.log('4')
})
},0)
new Promise(resolve=>{
console.log('5')
resolve();
}).then(()=>{
console.log('6')
})
setTimeout(()=>{
console.log('7');
},0)
setTimeout(()=>{
console.log('8');
new Promise(resolve=>{
console.log('9')
resolve();
}).then(()=>{
console.log('10')
})
},0)
new Promise(resolve=>{
console.log('11')
resolve();
}).then(()=>{
console.log('12')
})
console.log('13');
答案://1, 5,11,13,6,12,2,3,4,7,8,9,10
轉(zhuǎn) https://blog.csdn.net/qq_42833001/article/details/87252890
- 渲染幾萬條數(shù)據(jù)不卡住頁面借助請求動(dòng)畫幀requestAnimationFrame
/**
功能: 勻速滾動(dòng)到頁面頂部
@dom: 事件源DOM,
@speed: 總份數(shù)
*/
function scrollTopHandler(dom, speed = 500) {
// 滾動(dòng)的高度
let doc_scrollTop
let i = 0
// requestAnimationFrame 的執(zhí)行函數(shù)
const gotoTop = function() {
// 將滾動(dòng)高度分為1000份, 每份為unit的高度
const unit = doc_scrollTop / speed
// 每次執(zhí)行10份unit的距離
i += 10
// 計(jì)算每次滾動(dòng)的高度
const scrollTop = doc_scrollTop - i * unit > 0 ? doc_scrollTop - i * unit : 0
document.documentElement.scrollTop = scrollTop
// 判斷執(zhí)行分?jǐn)?shù)i小于speed 總分?jǐn)?shù),則繼續(xù)執(zhí)行
if (i <= speed) {
window.requestAnimationFrame(gotoTop)
} else {
// 重置
i = 0
}
}
// 點(diǎn)擊事件監(jiān)聽
const handler = function() {
doc_scrollTop = document.documentElement.scrollTop
window.requestAnimationFrame(gotoTop)
}
dom.addEventListener('click',handler,false)
}
// 調(diào)用方法
const dom = document.querySelector('#gotoTop')
scrollTopHandler(dom)
- ** 高頻算法**
算法面試必備
經(jīng)典冒泡排序
function bubbleSort(arr) {
for(let i = 0; i < arr.length - 1; i++){
for(let j = i + 1; j <= arr.length - 1; j++) {
if(arr[i] > arr[j]) {
const tempVal = arr[i]
arr[i] = arr[j]
arr[j] = tempVal
}
}
}
return arr
}
雙指針-快速排序
思想:來自于快速排序,在一個(gè)有序的數(shù)組(從小到大)中最左邊一定是最小值,最右邊是最大值。我們可將最小值與最大值相加與目標(biāo)值進(jìn)行比較,如果兩數(shù)之和大于目標(biāo)值,我們就讓最大值小一點(diǎn)(讀取第二個(gè)最大值),如果兩數(shù)之和小于目標(biāo)值,我們就讓最小值大一點(diǎn)(讀取第二個(gè)最小值),如果兩數(shù)之和剛好等于目標(biāo)值,保存最大值,最小值,并且讓最大值小一點(diǎn),最小值大一點(diǎn)。需要注意的是前提條件是數(shù)組必須有序!
function sum2(arr,tartgetVal) {
const resulutArr = []
const sortArr = arr.sort(function(a,b){
return a - b
})
let start = 0
let end = sortArr.length - 1
while(start < end) {
if (sortArr[start] + sortArr[end] === tartgetVal) {
resulutArr.push([sortArr[start], sortArr[end]])
start += 1
end -= 1
} else if (sortArr[start] + sortArr[end] >= tartgetVal) {
end -= 1
} else {
start += 1
}
}
console.log(resulutArr)
return resulutArr
}
const arr = [1, 4, 3, 2, 6, 5]
sum2(arr,6)
function sum3(arr, targetVal) {
const sortArr = arr.sort((a,b) => {
return a - b;
})
console.log(sortArr)
let result = []
const len = sortArr.length - 3
for(let i = 0; i < sortArr.length -3; i++) {
let left = i + 1, right = sortArr.length - 1
while(left < right) {
if(sortArr[i] + sortArr[left] + sortArr[right] === targetVal) {
result.push([sortArr[i], sortArr[left], sortArr[right]])
left += 1
right -= 1
} else if (sortArr[i] + sortArr[left] + sortArr[right] > targetVal) {
right -= 1
} else {
left += 1
}
}
}
console.log(result)
return result
}
const arr = [1, 4, 3, 2, 6, 5, 9, 8, 21, 22, 34, 10, 14]
sum3(arr, 10)
//
[Array(3), Array(3), Array(3)]
0: [1, 3, 6]
1: [1, 4, 5]
2: [2, 3, 5]
