简体   繁体   English

Scope,javascript 中的词法环境和执行上下文

[英]Scope, lexical environment and Execution Context in javascript

While playing with a script to automatically add event listeners, came to a situation when a varaible let activeModal;在玩脚本自动添加事件侦听器时,遇到了一个情况,当一个变量let activeModal; declared inside a function remains "alive" after function execution but a variable created inside another function let currentPlayTime;在 function 执行后在 function 中声明保持“活动”状态,但在另一个 function 中创建的变量let currentPlayTime; does not live after function execution. function 执行后不存在。 Making the let currentPlayTime;制作let currentPlayTime; variable global, as expected, obviously works.正如预期的那样,变量 global 显然有效。

My main question is why does variable let activeModal;我的主要问题是为什么变量let activeModal; "survive" after the function as finished? function 完成后“生存”?

Second question, how would I go about avoiding making let currentPlayTime;第二个问题,我将如何避免let currentPlayTime; global?全球的?

I suspect it has to do with Scope, lexical environment or Execution Context, but so far what I've read about such topics has left me a little puzzled.我怀疑它与 Scope、词汇环境或执行上下文有关,但到目前为止,我所读到的关于这些主题的内容让我有些困惑。 Regards.问候。

//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();
    }
  }

When you do this当你这样做时

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];

  }

You are basically telling the compiler to attach an event handler on each button.您基本上是在告诉编译器在每个按钮上附加一个事件处理程序。 Also, compiler whenever this callback function is called make sure that the activeModal is updated.此外,每当调用此回调 function 时,编译器确保更新activeModal

Now, you have created a dilemma for the compiler.现在,您为编译器制造了两难境地。 It likes to keep things clean.它喜欢保持东西干净。 Whever it gets the chance it cleans up unused references.只要有机会,它就会清理未使用的引用。 Now, it can't do that for the case of activeModal here because you have told it to update that value later when click handler is triggered.现在,对于此处的activeModal情况,它不能这样做,因为您已告诉它稍后在触发单击处理程序时更新该值。 So, it keeps it and you are able to use it.因此,它保留它并且您可以使用它。


Now, in your toggleAnimation function, the currentPlayTime is not getting accessed outside the scope of its parent function unlike the activeModal which is accessed by event handler which executed on the global scope. Now, in your toggleAnimation function, the currentPlayTime is not getting accessed outside the scope of its parent function unlike the activeModal which is accessed by event handler which executed on the global scope. So, once the toggleAnimation function is executed it just makes sense to clean up currentPlayTime.因此,一旦执行了toggleAnimation function,清理currentPlayTime.

If you want to avoid global variable, one way to achieve that is to make a function that returns another function creating a closure to safe keep currentPlayTime .如果你想避免全局变量,实现这一点的一种方法是制作一个 function ,它返回另一个 function 创建一个闭包以安全地保持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();
    }
  }
}

Now, you need to do现在,你需要做

const variableName = toggleAnimation();

variableName();

So here what happens is, toggleAnimation returns a function that would need currentPlayTime when it execute.所以这里发生的事情是, toggleAnimation返回一个 function,它在执行时需要currentPlayTime

This means the block enclosing the returned function will be necessary for its execution.这意味着包含返回的 function 的块将是其执行所必需的。 Hence, the compiler will keep hold of this closure, so that, whenever it is called it could be executed.因此,编译器将保留这个闭包,这样,无论何时调用它都可以执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM