在使用脚本自动添加事件侦听器时,遇到这样一种情况:在函数执行后声明的可变let activeModal;
在函数执行后保持"活动",但在另一个函数let currentPlayTime;
中创建的变量在函数执行后不存活。正如预期的那样,使let currentPlayTime;
变量全局显然有效。
我的主要问题是为什么变量let activeModal;
在函数完成后"存活"?
第二个问题,我将如何避免使let currentPlayTime;
全球化?
我怀疑这与范围、词汇环境或执行上下文有关,但到目前为止,我读到的有关此类主题的内容让我有点困惑。 问候。
//THIS WORKS
function addModalHandlers()
{
// Get the modal
let modalsCollection = document.getElementsByClassName("modal");
let btn = document.getElementsByClassName('stations-pointer');
let span = document.getElementsByClassName("close");
let modals = [];
let modalsContents = []
let activeModal; //<----RELEVANT POINT
console.log("modalsCollection");
console.log(modalsCollection);
//convert HTML Collection to array for later using Array.includes() method
for (let i=0;i<modalsCollection.length; i++)
{
modals[i] = modalsCollection[i]
// modals[i].style.opacity = "0";
}
// Attach event listeners to buttons to open the modals
for (let i=0;i<btn.length;i++)
{
btn[i].onclick = function() {
setTimeout(function (){
modals[i].style.display = "block";
console.log("TIMEOUT");
},1200);
activeModal = modals[i];
}
(...)
}
//THIS WORKS
let currentPlayTime;
function toggleAnimation()
{
console.log(path.style.transition);
if (path.style.transition == 'none 0s ease 0s')
{
toggleIcon()
console.log("currentPlayTime on play: "+currentPlayTime);
wavesurfer.play(currentPlayTime);
compatibleTransition(wavesurfer.getDuration() - currentPlayTime );
path.style.strokeDashoffset = 0;
}
else
{
toggleIcon()
path.style.strokeDashoffset = window.getComputedStyle(path).strokeDashoffset;
path.style.transition = 'none';
currentPlayTime = wavesurfer.getCurrentTime();
console.log("currentPlayTime on pause: "+currentPlayTime);
wavesurfer.pause();
}
}
//DOES NOT WORK
function toggleAnimation()
{
let currentPlayTime; //<---- SAME RATIONALE AS addModalHandlers() ABOVE BUT WORKS NOT
console.log(path.style.transition);
if (path.style.transition == 'none 0s ease 0s')
{
toggleIcon()
console.log("currentPlayTime on play: "+currentPlayTime);
wavesurfer.play(currentPlayTime);
compatibleTransition(wavesurfer.getDuration() - currentPlayTime );
path.style.strokeDashoffset = 0;
}
else
{
toggleIcon()
path.style.strokeDashoffset = window.getComputedStyle(path).strokeDashoffset;
path.style.transition = 'none';
currentPlayTime = wavesurfer.getCurrentTime();
console.log("currentPlayTime on pause: "+currentPlayTime);
wavesurfer.pause();
}
}
当你这样做时
for (let i=0;i<btn.length;i++) {
btn[i].onclick = function() {
setTimeout(function (){
modals[i].style.display = "block";
console.log("TIMEOUT");
},1200
);
activeModal = modals[i];
}
您基本上是在告诉编译器在每个按钮上附加一个事件处理程序。此外,每当调用此回调函数时,编译器都会确保更新activeModal
。
现在,您已经为编译器创建了一个困境。它喜欢保持清洁。无论它有机会清理未使用的引用。现在,对于此处activeModal
的情况,它无法执行此操作,因为您已经告诉它稍后在触发单击处理程序时更新该值。因此,它保留了它,您可以使用它。
现在,在toggleAnimation
函数中,与在全局范围内执行的事件处理程序访问的activeModal
不同,currentPlayTime
不会在其父函数的作用域之外访问。因此,一旦执行了toggleAnimation
函数,清理currentPlayTime.
就有意义
了如果你想避免全局变量,实现这一点的一种方法是创建一个函数,该函数返回另一个函数,创建一个闭包以安全保持currentPlayTime
。
function toggleAnimation() {
let currentPlayTime;
return function doDomething() {
if (path.style.transition == 'none 0s ease 0s') {
toggleIcon()
console.log("currentPlayTime on play: "+currentPlayTime);
wavesurfer.play(currentPlayTime);
compatibleTransition(wavesurfer.getDuration() - currentPlayTime );
path.style.strokeDashoffset = 0;
}
else {
toggleIcon()
path.style.strokeDashoffset = window.getComputedStyle(path).strokeDashoffset;
path.style.transition = 'none';
currentPlayTime = wavesurfer.getCurrentTime();
console.log("currentPlayTime on pause: "+currentPlayTime);
wavesurfer.pause();
}
}
}
现在,你需要做
const variableName = toggleAnimation();
variableName();
所以这里发生的事情是,toggleAnimation
返回一个在执行时需要currentPlayTime
的函数。
这意味着包含返回函数的块将是其执行所必需的。因此,编译器将保留此闭包,以便无论何时调用它都可以执行。