缓存
什么是缓存函数?
接收一个函数,用闭包将每次函数执行的结果缓存起来
缓存例子1:
/*
* 闭包实现缓存
* 属性:有个键--值 --->所以可以将缓存数据存放在一个对象中
* 方法:缓存存储 setCache
* 缓存的获取 getCache
* */
function configCache(){
var obj={};//设置一个内部的对象 用来存储缓存数据;这个属性是私有的
//对外暴露两个公共的方法
return {
setCache:function(k,v){//设置缓存
obj[k]=v;
},
getCache:function(k){//获取缓存
return obj[k];
}
};
}
var conf = configCache();
console.log(conf);
conf.setCache(1,'sdwqecwqv');
console.log(conf.getCache(1));//sdwqecwqv
/*
* 注意下面这种情况,两次configCache()会产生不同的执行环境
* */
configCache().setCache(1,'sdwqecwqv');
console.log(configCache().getCache(1));//undefined
/*
* 使用立即执行函数
* */
var cacheConfig = (function(){
var obj={};
return {
setCache:function(k,v){
obj[k]=v;
},
getCache:function(k){
return obj[k];
}
}
})();
上面代码能看到外部cache可以读取也可以设置useCache内部的data,由此实现了缓存。
缓存函数的应用场景
缓存函数-柯里化
const memoize = (fn) => {
const cache = {};
const func = (...args) => {
const key = JSON.stringify(args); // 函数入参序列化成string做为本次递归结果的唯一标识
return cache[key] || (cache[key] = fn.apply(null, args)); // 如果缓存中有则直接返回 否则执行本次递归并将结果和key存入缓存
};
return func;
};
例子1:求1到n的和优化
//使用缓存函数
const add = (n) => {
console.log('执行了一次');
if (n === 1) {
return 1;
}
return add(n - 1) + n;
};
const addFn = memoize(add);
console.log(addFn(3)); // 执行3次
console.log(addFn(3)); // 不会执行 缓存里有结果了 直接取
------------------------------------------------------------------------------------
//不使用
const useAdd = () => {
const cache = {};
const add = (n) => {
console.log('执行了', cache);
if (n === 1) {
return 1;
}
return cache[n] || (cache[n] = add(n - 1) + n); // 如果缓存有值取缓存,否则继续递归存入缓存
};
return add;
};
const add = useAdd();
console.log(add(3)); // 会调用3次
console.log(add(2)); // 2已经缓存过了 所以只调用一次 从缓存中取
例子2:求斐波那契数列优化
const useGetRabbit = () => {
const cache = {};
return function getRabbit(n) {
if (n === 1 || n === 2) {
return 1; // 出生后第三个月开始每个月才会生一对兔子,第三个月之前还是1对
}
return cache[n] || (cache[n] = getRabbit(n - 1) + getRabbit(n - 2)); // 如果缓存有就取缓存 否则当前月兔子对数取前两个月之和
};
};
const getRabbit = useGetRabbit();
console.log(getRabbit(48)); // 如果不用闭包缓存48个月就算不出来报栈溢出错误了
利用闭包及纯函数的特性来缓存函数每次调用的结果提高性能,避免重复的计算,使用时要注意一定要是个纯函数!
隔离变量
function useCache () {
const data = {};
const setItem = (key, value) => {
data[key] = value
}
const getItem = key => {
return data[key]
}
return {
state: {
data
},
getItem,
setItem
}
}
const cache = useCache()
console.log(cache.state.data);
cache.setItem('a', '1')
cache.getItem('a')
可以这样看,data、setItem、getItem是被隔离在useCache内的数据或方法,在外部可以读取到或调用,但也只有cache有这个权限。
函数柯里化
通俗的说,柯里化是指一个函数,他接收函数作为参数,运行后能够返回一个新的函数。并且这个新的函数能够处理函数A的剩余参数,完整柯里化通常依赖 JS 的闭包。
function curry(fn) {
let arr = [];
return function curried(...args) {
arr = [...arr, ...args]
if (arr.length > fn.length) {
return fn(...arr);
}
return curried;
}
}
function sum(a, b, c) {
return a * b * c;
}
let sum2 = curry(sum)
let sum3 = curry(sum)
console.log(sum2(1)(2)(2, 3)) // 4
console.log(sum3(1)(2)(3, 2)) // 6
上面的例子中,被传入的函数 fn 的调用时机,依赖于它自身的参数个数,当闭包属性 arr 长度达到要求后,才会被调用。这样的需求我个人感觉不多,那么函数柯里化的好处是什么?下面是柯里化更常用的一种场景:
// 更自由的组合参数
function createRequest(option, request) {
return function (args) {
return request({...option, ...args })
}
}
function request(option) {
return option;
}
let longRequest = createRequest({
timeout: 24 * 3600 * 1000
}, request)
let longAndUserRequest = createRequest({
api: '/user'
}, longRequest)
var res = longAndUserRequest({ name : '111' })
// api: "/user"
// name: "111"
// timeout: 86400000
它可以自由组合参数,让代码更简洁,比如 Function.prototype.bind 以及 axios.create 都使用了 函数柯里化的特性,我认为函数柯里化是一种设计模式,有点类似组合模式。这种组合方式缺点是:导致调用栈增加。
标签:闭包,function,缓存,const,cache,console,柯里化,return From: https://www.cnblogs.com/guibi/p/16867620.html