網站首頁 編程語言 正文
柯里化函數:
編程思想,函數執行,產生一個閉包,(不被釋放的上下文)把一些信息"預先存儲起來",目的是提供下級上下文中調使用,這樣的預先存儲思想,就叫做柯理化函數編程思想
作用域 vs上下文:
- 都是函數執行,在棧內存中所分配出來的空間
- 創建函數的時候,在那個上下文中創建的,那么其作用域就是誰(作用域不是函數自己執行產生的這個空間,而是創建函數所在的這個空間)
- 而上下文是函數自己執行產生的==>函數執行產生的私有上下文,它的上級上下文是它的作用域
應用場景
const fn = function fn(...params) {
// params[1,2]
return function proxy(...args) {
// args[3]
return params.concat(args).reduce((x, item) => x + item)
}
}
let res = fn(1, 2)(3)//fn(1,2)-->proxy(3)
console.log(res);
?了解:新版瀏覽器無法實現
add一直持續執行,執行幾次是不確定的,我們最后需要把每一次執行的值累加求和?
在瀏覽器沒有生級之前console.log(函數)會把函數轉換為字符串輸出
函數(Symbol.toPrimitive)-->函數.valueof()--->函數.tostring,但凡其中有一項返回了對象的值則控制臺以返回輸出為主,但是升級之后,轉換為字符串的操作還會觸發,但是控制臺最后呈現的還是函數
const curring = function curring() {
let params = [];
const add = (...args) => {
params = params.concat(args);
return add;
};
add[Symbol.toPrimitive] = () => params.reduce((result, item) => result + item);
return add;
};
let add = curring();
let res = add(1)(2)(3);
console.log(res); //->6
add = curring();
res = add(1, 2, 3)(4);
console.log(res); //->10
add = curring();
res = add(1)(2)(3)(4)(5);
console.log(res); //->15
函數式編程vs命令式編程
函數式編程:WHAT? 把具體執行的步驟封裝到一個函數中,后期需要處理的時候,只要把函數執行即可,我們不在關注執行的步驟,只關注后期處理結果
- 優點:低耦合好內聚,快捷化開發,方便維護
- 缺點:不能靈活掌握程序處理步驟,無法在某一個步驟做些特殊處理
命令式編程:HOW 更關注處理步驟,需要自己去實現每一步的操作
- 優點:靈活想怎么處理就怎么處理
- 缺點:代碼冗余度高,開發效率慢
真實項目中推薦使用函數式編程
栗子
// forEach就是函數式編程,函數內部實現了對數組迭代的封裝,每一次迭代都把回調函數執行,并且把當前迭代這一項及索引傳遞過來
let arr = [10, 20, 30]
arr.forEach((item, index) => {
console.log(item, index);
});
// 命令式編程
for (let i = 0; i < arr.length; i++) {
console.log(arr[i], i);
}
//封裝forEach
Array.prototype.forEach = function (callback) {
//this--->要操作的數組
let self = this;
for (let i = 0; i < self.length; i++) {
callback(self[i], i)
}
}
面試題:foreach和for循環的區別
forEach是數組內置的方法,內部對數組迭代進行了封裝,直接使用就可以 函數式編程,不支持以任何形式中斷它的迭代;forEach內部依次迭代每一項,每一次迭代把傳遞的回調函數執行,把迭代的內容及其索引傳遞給回調函數..直到這個數字迭代完畢
for循環是命令式編程,需要我們自己手動實現數組迭代,可以中斷,可以設置間隔幾個迭代
在項目開發的時候一般應用的是forEach,這樣可以提高我的開發效率,減少代碼冗余,但是遇到一些靈活的代碼需求,則自己基于for循環操作
?組合函數
/*
在函數式編程當中有一個很重要的概念就是函數組合, 實際上就是把處理數據的函數像管道一樣連接起來, 然后讓數據穿過管道得到最終的結果。 例如:
const add1 = (x) => x + 1;
const mul3 = (x) => x * 3;
const div2 = (x) => x / 2;
div2(mul3(add1(add1(0)))); //=>3
?
而這樣的寫法可讀性明顯太差了,我們可以構建一個compose函數,它接受任意多個函數作為參數(這些函數都只接受一個參數),然后compose返回的也是一個函數,達到以下的效果:
const operate = compose(div2, mul3, add1, add1)
operate(0) //=>相當于div2(mul3(add1(add1(0))))
operate(2) //=>相當于div2(mul3(add1(add1(2))))
?
簡而言之:compose可以把類似于f(g(h(x)))這種寫法簡化成compose(f, g, h)(x),請你完成 compose函數的編寫
*/
const add1 = x => x + 1;
const mul3 = x => x * 3;
const div2 = x => x / 2;
const compose = function compose(...funcs) {
//funcs:數組,一次存儲要執行的函數,而且從右到左的順序執行
return function operate(x) {
let len = funcs.length
// x 函數執行的初始值
if (len === 0) return x;//如果不傳初始值是啥返回啥
if (len === 1) return funs(0)(x)
return funcs.reduceRight((x, item) => {
return item(x)
}, x)
}
};
const operate = compose(div2, mul3, add1, add1)
console.log(operate(0));//=> 3 相當于div2(mul3(add1(add1(0))))
console.log(operate(2));//=>6
?惰性函數:懶 執行一次可以搞定,決對不會執行第二次
獲取元素樣式:
- getComputedStyle() 方法用于獲取指定元素的 CSS 樣式。
- currentStyle ie678
- 獲取的樣式是元素在瀏覽器中最終渲染效果的樣式。
封裝兼容獲取樣式方法
瑕疵:瀏覽器沒換,頁面沒關,第一次處理需要判斷兼容性是必須的,但是第二次即以后執行,如果還是要判斷兼容性是沒必要的
var getCss = function (elem, attr) {
if (window.getComputedStyle) {
getCss = function (elem, attr) {
return window.getComputedStyle(elem)[attr];
}
} else {
getCss = function (elem, attr) {
return elem.currentStyle[attr]
};
}
return getCss(elem, attr)
}
console.log(getCss(document.body, "margin"));
console.log(getCss(document.body, "padding"));
,函數的防抖和節流
防抖
防抖:防止"老年帕金森",在用戶頻繁點擊某項操作的時候,我們只識別一次{自定義頻繁規則,自定義觸發邊界}
const submit = document.getElementById('submit')
//模擬服務器異步獲取數據的操作
const query = callback => {
setTimeout(() => {
callback({
code: 0,
msg: "success"
})
}, 1000);
}
submit.onclick = function () {
console.log('click,start');
query(value => {
console.log(value);
})
}
簡單版本的防抖處理
點擊按鈕執行回調函數獲取數據,在上一次請求沒有完成之前,在次點擊按鈕不在執行callback獲取數據 設置標識
const submit = document.getElementById('submit')
let runing = false;//設置標識判斷
//點擊按鈕執行回調函數獲取數據,在上一次請求沒有完成之前,在次點擊按鈕不在執行callback獲取數據
submit.onclick = function () {
if (runing) return;//如果true 就不在執行
runing = true;//點擊之后把標識改為true
submit.disabled = true;//禁用按鈕
query(value => {
console.log(value);
runing = false;//當獲取數據之后,改為false
submit.disabled = false//恢復按鈕禁用
})
}
通用防抖方法的封裝處理?
思路:
- 假設:300ms內多次觸發事件,算做頻繁操作:
- 第一次點擊;等待300ms 設置定時器(執行具體要做的事情)
- 第二次點擊:...
- 每一次點擊都設置一個定時器,等待300ms,300ms之后執行要做的事情
- 如果定時器還沒有到時間,要做的事情還沒有干(300m以內)在次觸發這個事件,首先把之前設置的定時器清除掉,在重新設置一個新的
?掃盲:如何清除定時器
- timer是個數字 記錄第幾個定時器 例如1???clearTimeout(1/2 timer)清除第幾個定時器
- 問題:沒有任何的方法直接讓我們檢測這個定時器是否被清除掉,
- 所以我們每次設置定時器的時候,一般會把timer設置為null,設置定時器timer是個數字 代表定時器存在,清除定時器我們把timer也設置為null了,那以后我們只要判斷timer的值,只要這個值不是null,說明這個定時器沒有被清除掉,如果為null是被清除掉的
timer = setTimeout(() => {
func();
}, wait);
代碼
// submit.onclick =operate 瘋狂點擊,會觸發operate函數,我們要做的事情就是保證func(真實要干的事情,只執行一次)
const clearTimer = function clearTimer(timer) {
if (timer !== null) clearTimeout(timer)
return null
}
//不傳:debounce(函數)-->debounce(函數,300,false)
// debounce(函數, 300)-->debounce(函數,300,false)
// debounce(函數,true)-->debounce(函數,300,false)
const debounce = function debounce(func, wait, immediate) {
//func要做的事情 wait時間 事件綁定一定是函數
if (typeof func !== "function") throw new TypeError('func is not a function!')
if (typeof wait === "boolean") { immediate = wait; console.log(wait); };
if (typeof wait !== "number") { wait = 300; console.log(wait); }
if (typeof immediate !== "boolean") immediate = false;
let timer = null;
return function operate(...params) {
let now = !timer && immediate;
//清除之前設置的定時器,this-->submit
timer = clearTimer(timer)
timer = setTimeout(() => {
console.log(timer);
// 清除最后一次設置的定時器
timer = clearTimer(timer)
// 設置在結束邊界觸發
if (!immediate) func.apply(this, params)
}, wait);
// 設置開始邊界觸發
if (now) {
console.log('開始邊界', now); return func.apply(this, params)
}
}
}
//模擬服務器異步獲取數據的操作
const query = callback => {
setTimeout(() => {
callback({
code: 0,
msg: "success"
})
}, 1000);
}
const submit = document.getElementById('submit')
submit.onclick = debounce(function (ev) {
console.log("click start", ev);
console.log(this);
query(value => {
console.log(value);
})
})
節流
??window.onscroll//監聽瀏覽器滾動條事件(默認觸發頻率 按照瀏覽器最快反應時間)(谷歌5-7ms觸發,這樣的觸發頻率太快了,非常消耗性能)
節流:'降頻',在用戶頻繁點擊某項操作的時候,我們降低默認的觸發頻率
思路window.οnscrοll=throttle 滾動過程中,operate函數會間隔 5ms觸發一次,而我們編寫throttle方法的目的,是operate執行的過程中,控制要真正執行的func,間隔300ms觸發一次
- 第一次滾動,記錄當前觸發的時間,@A
- 間隔5ms第二次觸發的時候,拿當前觸發時間@A,和300做對比,發現還有295ms才應該去做func這件事,設置一個定時器
- 第三次及其以后觸發,如果發現目前已經有一個等待執行的定時器,就啥也不干即可...,
- 直到上一次設置的定時器已經執行(兩次間隔的時間超過300了),定時器已經被清掉了,此時我們在次設置一個定時器,還是讓其等待300ms之后執行
- 特殊情況 發現兩次時間差超過300,此時立即觸發
代碼
const clearTimer = function clearTimer(timer) {
if (timer !== null) clearTimeout(timer)
return null
}
const throttle = function throttle(func, wait) {
if (typeof func !== "function") throw new TypeError('func is not a function!')
if (typeof wait === "boolean") { immediate = wait };
let timer = null,
previous = 0;//記錄上一次觸發的時間
return function operate(...params) {
let now = +new Date(),//當前時間
remaining = wait - (now - previous)//兩次觸發的間隔時間跟300做對比
if (remaining <= 0) {
//說明兩次操作的間隔時間大于300的,此時立即觸發執行
timer = clearTimer(timer)
previous = +new Date;//把觸發時間記錄下來
func.apply(this, params)
}
//間隔時間差不足300,如果還沒有設置過定時器,則直接設置定時等著執行,如果已經設置過定時器啥事都不用干
if (!timer) {
timer = setTimeout(() => {
//清除定時器,保證每次定時器執行完為null
timer = clearTimer(timer)
previous = +new Date;//把觸發時間記錄下來
func.apply(this, params)
}, remaining)
}
}
}
window.onscroll = throttle(function (ev) {
console.log("scrolling");
}, 300)
原文鏈接:https://blog.csdn.net/qq_63358859/article/details/122261894
相關推薦
- 2022-08-05 C#實現圖形界面的時鐘_C#教程
- 2022-12-05 Golang中的錯誤處理的示例詳解_Golang
- 2022-04-19 css中link和@import的區別詳解
- 2022-08-10 Go?modules?replace解決Go依賴引用問題_Golang
- 2023-05-03 深入了解一下C語言中的柔性數組_C 語言
- 2022-05-02 C語言遞歸實現歸并排序詳解_C 語言
- 2021-11-28 linux手工配置ip地址詳細步驟_Linux
- 2022-12-14 正則表達式(?=)正向先行斷言實戰案例_正則表達式
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支