anti shake
- Anti-shake is only triggered once within a fixed period of time (that is, when clicking continuously, the stop time is greater than the specified value to trigger the event)
- Realized by timer and closure
function debounce(fun,ms=1000){
let timer; // 定义开关,当它为false时,定时器启动,为true时,清除掉上一个定时器
return function (...args){
if(timer){
clearTimeout(timer)
}
timer=setTimeout(()=>{
// 启动定时器,规定的防抖时间到了后再执行
fun.call(this,args)
timer=null
},ms)
}
}
const task=()=>{
console.log('大于设置时间间隔,事件触发')
}
const debounceTask=debounce(task,1000) // 定义事件函数,规定防抖事件为1000ms
/*
* 测试
* 当
* setInterval(()=>{
* console.log('一直触发事件中')
* debounceTask()
* },500)
* 也就是触发的频率大于规定的1000ms,控制台只打印’一直触发事件中‘,不会出现’大于设置时间间隔,事件触发‘
*/
setInterval(()=>{
console.log('一直触发事件中')
debounceTask()
},2000)
/*
* 这个触发频率大于1000ms,每个2000ms打印’一直触发事件中‘和’大于设置时间间隔,事件触发‘
*/
throttling
- Throttling is triggered every fixed event (that is, when you click continuously, no matter how often you click, an event is triggered every fixed event)
- It is also implemented with closure plus timer
function throttle(fun,ms=1000){
let canRun=true // 定义开关,默认为true,会启动定时器,false时,在判断语句中结束掉进程
return function (...args){
if(!canRun){
return } // 当canRun为false时触发,也就是已经有一个定时器执行着,就结束该进程;也就是在此处截断
canRun=false // 将canRun的状态改为false,那么在里面定时器执行完毕之前不会再向后走,也就是阻止后面事件触发时响应
setTimeout(()=>{
fun.apply(this,args)
canRun=true // 执行完毕后,允许后面事件进来响应
},ms)
}
}
const task=()=>{
console.log('大于设置时间间隔,事件触发')
}
const throttleTask=throttle(task,1000)
/*
* 测试
* 虽然执行频率为500ms一次,但控制台依然1000ms打印一次’大于设置时间间隔,事件触发‘
* 控制台打印
* 一直触发事件中
* 一直触发事件中
* 大于设置时间间隔,事件触发
* 一直触发事件中
* 一直触发事件中
* 大于设置时间间隔,事件触发
*/
setInterval(()=>{
console.log('一直触发事件中')
throttleTask()
},500)
Note: You can use lodash to complete anti-shake and throttling
new
- ES6 syntactic sugar class principle
function myNew(Func,...args){
const instance={
}
if(Func.prototype){
// 如果函数原型存在,将instance指向原型对象上去
Object.setPrototypeOf(instance,Func.prototype)
}
const res=Func.apply(instance,args) // 调用构造器,并将内部的this用instance来代替
if(typeof res==='function' || typeof res==='object' && typeof res===null){
// 兼容处理下返回值
return res
}
return instance
}
function Person(name){
this.name=name
}
Person.prototype.eat=function (){
console.log(this.name+'吃饭')
}
const p1=myNew(Person,'jakc')
p1.eat()
// jack吃饭
Currying
- Function currying means that we pass in some parameters to a function, and then a function will be returned to receive the remaining parameters, and the returned function will be executed later
- Split one parameter of a function into two or more parameters
function curry(func){
return function curried(...args){
// 传入的参数大于等于原始函数func的参数个数,则直接执行该函数
if(args.length >= func.length){
return func.apply(this, args)
}
/**
* 传入的参数小于原始函数fn的参数个数时
* 则继续对当前函数进行柯里化,返回一个接受所有参数(当前参数和剩余参数) 的函数
*/
return function (...args2){
return curried.apply(this,args.concat(args2))
}
}
}
function sum(a,b,c){
return a+b+c
}
const curriedSum=curry(sum)
console.log(curriedSum(1,2,3))
console.log(curriedSum(1)(2,3))
console.log(curriedSum(1)(2)(3))
// 输出结果都为6
flat data
const newArr=[
{
id: 'a',
pid: 0,
value: '陕西',
children:[
{
id: 1,
pid: 'a',
value: '西安',
children:[
{
id: 301, pid: 1, value: '雁塔区'},
{
id: 302, pid: 1, value: '高新区'}
]
},
{
id: 2,
pid: 'a',
value: '渭南',
children:[]
},
{
id: 3,
pid: 'a',
value: '咸阳',
children:[]
},
]
},
{
id: 'b',
pid: 0,
value: '广东',
children:[
{
id: 11, pid: 'b', value: '广州',children:[]
},
{
id: 12, pid: 'b', value: '深圳',children:[]
},
{
id: 13, pid: 'b', value: '潮汕', children:[]
}
]
}
]
function toLine(data,result=[]){
data.forEach(item=>{
if(item.children){
result.push({
id:item.id,
pid:item.pid,
value:item.value,
})
toLine(item.children,result)
}else {
result.push({
id:item.id,
pid:item.pid,
value:item.value,
})
}
})
return result
}
toLine(newArr)
Flattened data
[
{
id: 'a', pid: 0, value: '陕西'},
{
id: 1, pid: 'a', value: '西安'},
{
id: 301, pid: 1, value: '雁塔区'},
{
id: 302, pid: 1, value: '高新区'},
{
id: 2, pid: 'a', value: '渭南'},
{
id: 3, pid: 'a', value: '咸阳'},
{
id: 'b', pid: 0, value: '广东'},
{
id: 11, pid: 'b', value: '广州'},
{
id: 12, pid: 'b', value: '深圳'},
{
id: 13, pid: 'b', value: '潮汕'},
]
tree data
var data=[
{
pid:0,id:'a',value:'陕西'},
{
pid:'a',id:1,value:'西安'},
{
pid:1,id:301,value:'雁塔区'},
{
pid:1,id:302,value:'高新区'},
{
pid:'a',id:2,value:'渭南'},
{
pid:'a',id:3,value:'咸阳'},
{
pid:0,id:'b',value:'广东'},
{
pid:'b',id:11,value:'广州'},
{
pid:'b',id:12,value:'深圳'},
{
pid:'b',id:13,value:'潮汕'},
];
function toTree(data,pid) {
function tree(pid){
let arr=[]
data.filter(item=> {
return item.pid === pid // 过滤下与传入的pid(最顶层的pid号)相等的item,也就代表是最顶层,
}).forEach(item=>{
arr.push({
id:item.id,
pid:item.pid,
value:item.value,
children:tree(item.id) // 递归调用tree,渲染相同id的一组
})
})
return arr
}
return tree(pid)
}
const newArr=toTree(data,0) // 传入的0代表最顶层数据的pid是0
Tree structure after rendering
[
{
id: 'a',
pid: 0,
value: '陕西',
children:[
{
id: 1,
pid: 'a',
value: '西安',
children:[
{
id: 301, pid: 1, value: '雁塔区'},
{
id: 302, pid: 1, value: '高新区'}
]
},
{
id: 2,
pid: 'a',
value: '渭南',
children:[]
},
{
id: 3,
pid: 'a',
value: '咸阳',
children:[]
},
]
},
{
id: 'b',
pid: 0,
value: '广东',
children:[
{
id: 11, pid: 'b', value: '广州',children:[]
},
{
id: 12, pid: 'b', value: '深圳',children:[]
},
{
id: 13, pid: 'b', value: '潮汕', children:[]
}
]
}
]