今天在封装运动函数的时候遇到了一个由于不报缓存形成的问题,接下来分享给大家,在写的不透彻的地方欢迎各位能够指正,谢谢啦!
我想要封装的函数是一个物体先加速后减速的直线运动,就在封装完成之后遇到了一些问题。话不多说上代码:
function normal(tarPos, target) {
let timer = null;
return function () {
clearInterval(timer);
let speed = null;
timer = setInterval(() => {
speed = (tarPos - target.offsetLeft) / 7;
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
if (target.offsetLeft == tarPos) {
clearInterval(timer);
} else {
target.style.left = target.offsetLeft + speed + 'px';
}
}, 50);
}
}
wapper.onmouseenter = function () {
normal(0, wapper)();
console.log(1);
};
wapper.onmouseleave = function () {
normal(-400, wapper)()
console.log(2);
}
遇到的问题就是当,鼠标放到目标区域后只有在函数 normal 全部执行后,才可以让鼠标移出,不然就在物体还没有遇到到指定的目标位置,onmouseleave 事件就会被触发,执行 onmouseleave 事件中的 normal 函数。两个操作就会出现互斥现象。
出现这种互斥现象的原因就是,在封装函数的时候,向函数外部返回了一个匿名函数,这个匿名函数在外部调用的时候,就形成了闭包。在函数 normal 和匿名函数之间又形成了一个存储区域,在这个区域声明的变量外部无法访问,只有函数 normal 内部可以访问。但是就在每次鼠标移入和移出的时候都会形成一个性的 timer 变量,并且每一个timer 都一样,操纵的定时器也是不同的。 所以就会出现互斥现象,那么解决这个由于闭包出现的错误也很简单,直接在 target 上加一个属性 timer,由于事件onmouseenter 和 onmouseleave传入的 target 相同,所以实在操作同一个timer,也就是同一个定时器。
修改后代码如下:
wapper.addEventListener('mouseenter', normal(0, wapper))
wapper.addEventListener('mouseleave', normal(-400, wapper))
// 先加速后减速
function normal(tarPos, target) {
return function () {
// speed = step / 9;
clearInterval(target.timer);
let speed = null;
target.timer = setInterval(() => {
speed = (tarPos - target.offsetLeft) / 7;
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
if (target.offsetLeft == tarPos) {
clearInterval(target.timer);
} else {
target.style.left = target.offsetLeft + speed + 'px';
}
}, 50);
}
}