1. 实现curry()
请实现一个
curry()方法,接受一个function然后返回一个柯里化过后的function
栗子:
const join = (a, b, c) => {
return `${a}_${b}_${c}`
}
const curriedJoin = curry(join)
curriedJoin(1, 2, 3) // '1_2_3'
curriedJoin(1)(2, 3) // '1_2_3'
curriedJoin(1, 2)(3) // '1_2_3'
实现:
- 递归实现
- 每次调用收集参数,直到参数个数等于传入函数的参数个数就执行传入函数
代码:
/**
* @param { (...args: any[]) => any } fn
* @returns { (...args: any[]) => any }
*/
function curry(fn) {
// your code here
return function myCurry(...args) {
if (args.length>=fn.length) {
return fn(...args)
} else {
return (...args2) => {
return myCurry(...args,...args2)
};
}
}
}
2. 实现支持placeholder的curry()
请实现一个支持placeholder的
curry(),可以像这样使用。placeholder为占位符形式。
栗子:
const join = (a, b, c) => {
return `${a}_${b}_${c}`
}
const curriedJoin = curry(join)
const _ = curry.placeholder
curriedJoin(1, 2, 3) // '1_2_3'
curriedJoin(_, 2)(1, 3) // '1_2_3'
curriedJoin(_, _, _)(1)(_, 3)(2) // '1_2_3'
实现:
- 递归实现
- 判断complate,所有的参数不包含placeholder,并且参数长度和传入函数参数长度一样
- 后面的参数要替换前面的placeholder
代码:
/**
* @param { (...args: any[]) => any } fn
* @returns { (...args: any[]) => any }
*/
function curry(fn) {
// your code here
return function myCurry(...args) {
let complate = args.length >= fn.length && args.slice(0, fn.length - 1).every(ele => ele !== curry.placeholder);
if (complate) {
return fn(...args)
} else {
return (...args2) => {
const args22 = args2;
let curryArgs = args.map(ele => {
if (ele === curry.placeholder && args22.length > 0) {
return args22.shift()
} else {
return ele
}
});
if (args22.length > 0) {
curryArgs.push(...args22)
}
return myCurry(...curryArgs)
};
}
}
}
curry.placeholder = Symbol();
3. 实现Array.prototype.flat()
Array.prototype.flat()可以用来扁平化数组。你能够自己实现一个flat么?
栗子:
const arr = [1, [2], [3, [4]]];
flat(arr)
// [1, 2, 3, [4]]
flat(arr, 1)
// [1, 2, 3, [4]]
flat(arr, 2)
// [1, 2, 3, 4]
实现:
- 递归实现
- 判断complate,depth为0或者所有元素都不是数组类型
- 每层处理后depth-1
代码:
/**
* @param { Array } arr
* @param { number } depth
* @returns { Array }
*/
function flat(arr, depth = 1) {
// your imeplementation here
const complate = depth === 0 || arr.every(item => !(item instanceof Array));
if (complate) return arr;
let res = [];
arr.forEach(item => {
if (item instanceof Array) {
res.push(...item)
} else {
res.push(item)
}
})
return flat(res, depth - 1)
}
本文使用 markdown.com.cn 排版
4. 手写throttle()
请实现一个
throttle()方法,throttle(func, delay)返回一个function,这个function无论多么频繁地调用,原始的func的调用也不会超过指定的频率。
栗子:
─A─B─C─ ─D─ ─ ─ ─ ─ ─ E─ ─F─G
按照3个单位进行throttle过后
─A─ ─ ─C─ ─ ─D ─ ─ ─ ─ E─ ─ ─G
A因为不在任何的冷却时间,所以立即被执行
B被跳过了,因为B和C都在A的冷却时间里。
实现:
- 返回一个函数return ()=>{}
- 闭包记录最后一次参数lastArgs
- 在冷却时间内就保存参数lastArgs,否则返回执行函数
代码:
/**
* @param {(...args:any[]) => any} func
* @param {number} wait
* @returns {(...args:any[]) => any}
*/
function throttle(func, wait) {
let waitting = false;
let lastArgs = null;
return (...args)=>{
//如果不在冷却中
if(!waitting){
waitting = true;
setTimeout(()=>{
//经过wait时间再刷新冷却waitting
waitting = false;
//如果lastArgs不为空就返回保存的参数的执行函数func(...lastArgs)
if(lastArgs) return func(...lastArgs);
},wait)
return func(...args);
}else{
//如果在冷却中就保存lastArgs
lastArgs = args
}
}
}
5. 手写throttle()并支持leading 和 trailing
实现一个增强的
throttle(),使其支持第三个参数option: {leading: boolean, trailing: boolean}
- leading: 是否立即执行
- trailing: 是否在冷却后执行
栗子:
同样地按照之前的3单位的throttle来举例。
─A─B─C─ ─D─ ─ ─ ─ ─ ─ E─ ─F─G
用{leading: true, trailing: true}来throttle后,我们得到
─A─ ─ ─C─ ─ ─D ─ ─ ─ ─ E─ ─ ─G
如果是 {leading: false, trailing: true},A 和 E 被跳过了
─ ─ ─ ─C─ ─ ─D─ ─ ─ ─ ─ ─ ─G
如果是 {leading: true, trailing: false},只有 A D E 被保留
─A─ ─ ─ ─D─ ─ ─ ─ ─ ─ E
如果是 {leading: false, trailing: false},显而易见,什么都不会发生
实现:
- 返回一个函数return ()=>{}
- 闭包记录最后一次参数lastArgs
- 如果有timer就表示冷却中,如果没有立即执行就保存参数
代码:
/**
* @param {(...args: any[]) => any} func
* @param {number} wait
* @param {boolean} option.leading
* @param {boolean} option.trailing
* @returns {(...args: any[]) => any}
*/
function throttle(func, wait, option = {leading: true, trailing: true}) {
const {leading, trailing} = option;
let lastArgs = null;
let that = null;
let timer = null;
//返回的函数
return (...args)=>{
that = this;
//如果存在定时器,就是在冷却中
if(timer){
lastArgs = args;
return
}
//如果是立即执行就执行,否则保存参数
if(leading){
func.call(that,...args)
}else{
lastArgs = args;
}
//设置冷却定时器
timer = setTimeout(()=>{
//如果trailing,否则完成冷却
if(trailing && lastArgs){
func.call(that,...lastArgs)
lastArgs = null;
that = null;
//trailing之后要再设置冷却,并且在冷却之后要继续trailing
setTimeout(()=>{
timer = null;
if(trailing && lastArgs){
func.call(that,...lastArgs)
lastArgs = null;
that = null;
}
},wait)
}else{
timer = null
}
},wait)
}
}
未完待续。。。