(鸡汤文)这一次我终于搞懂了 JavaScript 定时器的 this 指向!

简介: 忽然有一种感觉,每次学习一个知识点就像是谈一场恋爱:从初次邂逅,到彼此了解,一切都那么的符合恋爱的过程!

开篇语


忽然有一种感觉,每次学习一个知识点就像是谈一场恋爱:从初次邂逅,到彼此了解,一切都那么的符合恋爱的过程!


如果这个知识点再有点”调皮“的话,那简直是让人欲仙欲死而又不可自拔!因为你永远不知道它还有多少面纱等着你揭开,当你自以为对它已经足够了解的时候,冷不防就是一个盲点迎面砸来。


它简直就像一个”宝藏女孩“,你要时刻做好迎接”惊喜“的准备!


可能正是因为这种新鲜感,我才能一直保持一种类似亢奋的状态吧。当然,这只是针对知识而言,对待情感我还是很保守很专一的<( ̄︶ ̄)>


7.png


这两天,我就在和定时器谈恋爱,哦不,是在学习定时器( ̄▽ ̄)~*,可没想到,又给陷进去了……


这不,上一篇文章写完定时器的返回值后,刚觉得自己对它已经了解的清清楚楚明明白白了,够我炫耀一阵子了,谁成想,喘口气的功夫,它又给我整出了幺蛾子。


惑起


写完上篇文章后,我就琢磨着里面的实现代码还可以优化一下,于是给改成了下面这个样子:


<form action="" class="example-form">
    <div>
        <label for="name">
            名称
        </label>
        <input class="input-ele" type="text" name="name" id="name" placeholder="please input your name"
            autocomplete="off">
    </div>
    <div style="margin-top:50px;">
        <label for="res">
            输入
        </label>
        <textarea class="input-ele" type="multipart" name="res" id="res" readonly
            placeholder="这里是每一次输入的结果"></textarea>
    </div>
</form>
<script>
    window.onload = function () {
        const resEle = document.querySelector("#res");
        function changeOutputVal() {
            resEle.value += `\n${ this.value }`;
        }
        function throttle(fun, delay) {
            let last, deferTimer
            return function () {
                let now = Date.now();
                if (last && now < last + delay) {
                    clearTimeout(deferTimer);
                    deferTimer = setTimeout(function () {
                        last = now;
                        fun.apply(this);
                    }, delay)
                } else {
                    last = now;
                    fun.apply(this);
                }
            }
        }
        const inputEle = document.querySelector("#name");
        inputEle.addEventListener("input", throttle(changeOutputVal, 1000));
    }
</script>


我的修改依据是:


  1. throttle 方法返回的是一个匿名函数,这个函数正好充当 input 事件的回调函数
  2. input 事件回调函数中的 this 指向的是 inputEle
  3. 匿名函数中将 this 绑定给了 fun 参数,而实际使用中传入的是 changeOutputVal 方法
  4. 所以 changeOutputVal 方法中的 this 指的就是 inputEle,所以在它里面可以通过 this.value 获取到 inputEle 的值


看,这逻辑多严谨,简直头头是道啊 \( ̄︶ ̄)/


按理说,是没问题的吧,结果却出问题了。欲知详情,请看大屏幕:


8.png


这个 undefined 是什么鬼?!从哪冒出来的?难道我的延时器没用对?


解惑


面对我的质疑,setTimeout 理直气壮地说:人家回调函数中的 this 本来就是指向 window 对象的嘛,你也没早问啊!


那么,问题来了:为什么延时器中的 this 指向的是 window 呢?setTimeout 自己也解释不清楚了。


得,看来前人诚不我欺也——自己动手,丰衣足食!


凡事不决找 MDN,绝对靠谱!我们来看看 MDN 怎么说:


setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。这会导致,这些代码中包含的 this 关键字在非严格模式会指向 window (或全局)对象,严格模式下为 undefined,这和所期望的this的值是不一样的。


看到这个解释,我才明白:this 指向 window 对象,原来是因为执行环境的不同导致的。


在上面的代码中,因为 window 对象没有 value 这个属性,所以 window.value = undefined


感觉自己在专业的方向上又迈进了一小步,容我小小地嘚瑟一下!


9.png


改错


既然知道问题出在哪,那就好办了,我们只需要将 setTimeout 回到函数内部的 this 指向改变一下就好,这里有以下方案。


使用变量引用外部 this


关键代码如下:


window.onload = function () {
    // some code here
    const that = this;
    deferTimer = setTimeout(function () {
        last = now;
        fun.apply(that);
    }, delay)
    // some code here
}


使用箭头函数


利用箭头函数不会改变 this 的指向的特性,改造如下:


window.onload = function () {
    // some code here
    deferTimer = setTimeout(() => {
        last = now;
        fun.apply(this);
    }, delay)
    // some code here
}

结束语


知错能改,善莫大焉!


写到这里,我居然体会到了古人那种”朝闻道,夕死可矣“的满足感。


在编程这条路上,可能遍布荆棘,但只要我们勤耕不辍,总能开辟出属于自己的康庄大道!


这鸡汤太美味,我先干为敬,你们随意!b( ̄▽ ̄)d


~ 本文完,感谢阅读!


学习有趣的知识,结识有趣的朋友,塑造有趣的灵魂!


你来,怀揣期望,我有墨香相迎! 你归,无论得失,唯以余韵相赠!

知识与技能并重,内力和外功兼修,理论和实践两手都要抓、两手都要硬!




相关文章
|
2月前
|
JavaScript 前端开发 安全
JavaScript基础-定时器:setTimeout, setInterval
【6月更文挑战第13天】JavaScript中的`setTimeout`和`setInterval`是异步编程的关键工具,用于按计划执行代码。`setTimeout`在延迟后执行一次,而`setInterval`则周期性执行。常见问题包括忘记清除定时器导致内存泄漏,递归使用`setTimeout`可能引发无限递归,以及字符串代码执行的安全隐患。解决方法包括使用`clearTimeout`和`clearInterval`,设置递归终止条件,以及优先使用函数表达式。理解定时器的非精确性并采用错误处理策略也是实践中的重要技巧。通过示例展示了如何延迟显示消息和周期性打印计数。
|
5天前
|
JavaScript 前端开发
解决在JS中阻止定时器“重复”开启问题、Vue中定时器的使用
这篇文章讨论了在JavaScript和Vue中如何避免定时器重复开启的问题,并提供了一个模拟场景和代码示例,演示了在开启新定时器前清除旧定时器的方法。
解决在JS中阻止定时器“重复”开启问题、Vue中定时器的使用
|
5天前
|
JavaScript 前端开发
js之永久定时器
js之永久定时器
|
5天前
|
JavaScript 前端开发
|
8天前
|
Web App开发 JavaScript 前端开发
JavaScript——定时器为什么是不精确的
JavaScript——定时器为什么是不精确的
15 0
|
8天前
|
JavaScript 前端开发
js之永久定时器
js之永久定时器
13 0
|
8天前
|
JavaScript 前端开发
js之一次性定时器
js之一次性定时器
15 0
|
1月前
|
JavaScript 前端开发
vue 模拟随机变速的动态打字特效【支持多行文本】(含css实现闪烁光标,js动态改变setInterval定时器的时间间隔)
vue 模拟随机变速的动态打字特效【支持多行文本】(含css实现闪烁光标,js动态改变setInterval定时器的时间间隔)
35 1
|
2月前
|
JavaScript 前端开发
杨老师课堂之JavaScript定时器案例的红绿灯设计
杨老师课堂之JavaScript定时器案例的红绿灯设计
29 1
|
2月前
|
自然语言处理 JavaScript 前端开发
在JavaScript中,this关键字的行为可能会因函数的调用方式而异
【6月更文挑战第15天】JavaScript的`this`根据调用方式变化:非严格模式下直接调用时指向全局对象(浏览器为window),严格模式下为undefined。作为对象方法时,`this`指对象本身。用`new`调用构造函数时,`this`指新实例。`call`,`apply`,`bind`可显式设定`this`值。箭头函数和绑定方法有助于管理复杂场景中的`this`行为。
49 3

热门文章

最新文章