You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript闭包未捕获var变量 scrollHeight取值始终为0问题

Chrome下滚动深度追踪代码scrollHeight取值为0异常分析

问题对应代码实现

(function() {
  var debounce = function(func, delay) {
    var inDebounce;
    return function() {
      var context = this;
      var args = arguments;
      clearTimeout(inDebounce);
      inDebounce = setTimeout(function() {
        func.apply(context, args);
      }, delay);
    }
  }
  var scrollHeight = document.documentElement.scrollHeight - window.innerHeight;
  var quarterHeight = scrollHeight / 4;
  var quarters = 0;
  var scrollDistance, divisible, percent;
  document.addEventListener("scroll", debounce(function() {
    scrollDistance = window.pageYOffset || (document.documentElement || document.body.parentNode || document.body).scrollTop;
    divisible = Math.trunc(scrollDistance / quarterHeight);
    if (quarters < divisible) {
      scrollPercent = divisible * 25;
      heap.track('Scroll Depth', {
        percent: scrollPercent
      });
      quarters++;
    }
  }, 100));
}());

问题现象

在Chrome浏览器测试上述带防抖的滚动深度追踪代码时,事件监听器回调内依赖的scrollHeight相关计算值始终为0,表现类似闭包未捕获var声明的scrollHeight变量;将scrollHeight的赋值语句移动到闭包内部后,代码功能可正常运行。

异常产生原因

这个问题和闭包捕获逻辑没有关系,核心是代码执行时机错误导致初始值异常,且初始值不会自动更新:

  • 这段立即执行函数如果在DOM树构建完成前就运行(比如放在页面<head>标签内、未等待DOM加载就直接执行),浏览器还没完成页面内容的排版计算,此时读取document.documentElement.scrollHeight得到的结果就是0。
  • scrollHeight和依赖它计算的quarterHeight都是在立即执行函数的初始化阶段完成赋值的,闭包捕获的是这两个变量的固定初始值,后续哪怕DOM加载完成、页面总高度发生变化,这两个变量也不会自动重新计算,所以滚动触发回调时用到的quarterHeight始终是初始算出来的0,自然会出现计算异常。
  • 把scrollHeight的赋值逻辑移到滚动事件的回调内部后,首次触发滚动时DOM必然已经完成渲染,每次执行回调都会实时读取当前的页面总滚动高度,就能拿到正确的计算结果,功能恢复正常。

内容的提问来源于stack exchange,提问作者erotsppa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 02:06:32