Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >(鸡汤文)这一次我终于搞懂了 JavaScript 定时器的 this 指向!

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

原创
作者头像
编程三昧
修改于 2021-06-21 03:07:32
修改于 2021-06-21 03:07:32
3180
举报
文章被收录于专栏:编程三昧编程三昧

开篇语

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

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

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

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

宝藏女孩
宝藏女孩

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

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

惑起

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

代码语言:txt
AI代码解释
复制
<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, deferTime

            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 的值

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

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

错误结果
错误结果

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

解惑

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

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

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

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

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

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

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

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

嘚瑟
嘚瑟

改错

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

使用变量引用外部 this

关键代码如下:

代码语言:txt
AI代码解释
复制
window.onload = function () {

    // some code here

    

    const that = this;

    deferTimer = setTimeout(function () {

        last = now;

        fun.apply(that);

    }, delay)

    

    // some code here

}

使用箭头函数

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

代码语言:txt
AI代码解释
复制
window.onload = function () {

    // some code here

    

    deferTimer = setTimeout(() => {

        last = now;

        fun.apply(this);

    }, delay)

    

    // some code here

}

结束语

知错能改,善莫大焉!

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

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

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

~

~

~ 本文完,感谢阅读!

~

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

我是〖编程三昧〗的作者 **隐逸王**,我的公众号是『编程三昧』,欢迎关注,希望大家多多指教!

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

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
前端 JavaScript 之『节流』的简单代码实现
首先,总结一下上一篇文章——《前端 JavaScript 之『防抖』的简单代码实现》的内容:「防抖」就是在高频率触发事件停止触发后,延时执行某个处理逻辑。
编程三昧
2021/06/19
5430
前端 JavaScript 之『节流』的简单代码实现
前端 JavaScript 之『节流』的简单代码实现
首先,总结一下上一篇文章——《前端 JavaScript 之『防抖』的简单代码实现》的内容:「防抖」就是在高频率触发事件停止触发后,延时执行某个处理逻辑。
编程三昧
2021/06/19
4710
前端 JavaScript 之『节流』的简单代码实现
详谈js防抖和节流
函数防抖是某一段时间内只执行一次;而函数节流是间隔时间执行,不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数。
前端林子
2018/10/20
5.6K1
详谈js防抖和节流
阿里前端一面面试题(附答案)
V8 实现了准确式 GC,GC 算法采用了分代式垃圾回收机制。因此,V8 将内存(堆)分为新生代和老生代两部分。
gogo2027
2022/09/12
6930
防抖和节流 原
浏览器的一些事件,如:resize,scroll,keydown,keyup,keypress,mousemove等。这些事件触发频率太过频繁,绑定在这些事件上的回调函数会不停的被调用。会加重浏览器的负担,导致用户体验非常糟糕,不知哪个大神发明了防抖和节流,用来控制回调函数的次数。
tianyawhl
2019/04/04
8050
让你瞬间提高工作效率的常用js函数汇总(持续更新)
本文总结了项目开发过程中常用的js函数和正则,意在提高大家平时的开发效率,具体内容如下:
徐小夕
2019/08/09
8940
让你瞬间提高工作效率的常用js函数汇总(持续更新)
JavaScript 定时器 setTimeout、setInterval
定时器在javascript中的作用 1、制作动画 2、异步操作 3、函数缓冲与节流 定时器类型及语法 示例代码如下: /* 定时器: setTimeout 只执行一次的定时器 clearTimeout 关闭只执行一次的定时器 setInterval 反复执行的定时器 clearInterval 关闭反复执行的定时器 */ var time1 = setTimeout(myalert,2000); var time2 = setInterval(
Devops海洋的渔夫
2019/05/30
1K0
【如果你要学JS {十一}】——window常见事件,灵活运用定时器
BOM ( Browser Object Model )即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心 对象是window,BOM由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。 BOM缺乏标准, JavaScript 语法的标准化组织是ECMA , DOM的标准化组织是W3C , BOM最初是Netscape浏 览器标准的一部分。
像素人
2023/12/24
1.1K0
【如果你要学JS {十一}】——window常见事件,灵活运用定时器
让你瞬间提高工作效率的常用js函数汇总(持续更新)
本文总结了项目开发过程中常用的js函数和正则,意在提高大家平时的开发效率,具体内容如下:
徐小夕
2019/07/27
7540
让你瞬间提高工作效率的常用js函数汇总(持续更新)
JavaScript防抖节流函数
防止一个事件频繁触发回调函数的方式: 防抖动:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。 节流:使得一定时间内只触发一次函数。 它和防抖动最大的区别就是,节流函数不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而防抖动只是在最后一次事件后才触发一次函数。 原理是通过判断是否到达一定时间来触发函数,若没到规定时间则使用计时器延后,而下一次事件则会重新设定计时器。
Jack Chen
2018/09/14
6310
JavaScript 高频函数优化-函数防抖&函数节流
什么是高频函数? oninput(实时获取输入的数据) onscroll(监听页面的滚动) onresize(监听浏览器可视区域的变化) onmousemove(移动端监听手指在屏幕的滑动) 什么是函
前端小tips
2021/11/24
3940
JavaScript 高频函数优化-函数防抖&函数节流
JavaScript面试题
1、实现一个call函数 // 思路:将要改变this指向的方法挂到目标this上执行并返回 Function.prototype.mycall = function (context) { if (typeof this !== 'function') { throw new TypeError('not funciton') } context = context || window context.fn = this let arg = [...arguments].sl
挨踢小子部落阁
2019/08/13
6150
js底层原理,助你更好的完成技术上的提升
1. 实现一个call函数 // 思路:将要改变this指向的方法挂到目标this上执行并返回 Function.prototype.mycall = function (context) { if (typeof this !== 'function') { throw new TypeError('not funciton') } context = context || window context.fn = this let arg = [...arguments].sl
前端老鸟
2019/07/31
7070
JS基础第三课(定时器篇)
(1)概念:回调函数其实是一个参数,将这个函数作为参数传到别的函数里面,回调函数是最后执行的
申小兮
2023/04/14
2.1K0
JS基础第三课(定时器篇)
JavaScript高级技巧
以上代码要返回true,value必须是一个数组,而且还必须与Array构造函数在同个全局作用域中。(Array是window的属性)如果value是在另外一个iframe中定义的数组,上述代码则返回false。 注意:BOM的核心对象时window,它表示浏览器的一个实例。在浏览器中,window对象有双重角色,它既是通过JavaScript访问浏览器窗口的一个接口,又是ECMAScript规定的global对象。 解决上述问题: Object原生的toString()方法,都会返回一个[object NativeConstructorName]格式的字符串。
奋飛
2019/08/15
1.2K0
什么是BOM
BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window。
清出于兰
2020/10/26
1.1K0
什么是BOM
【建议】记录一次BAT一线互联网公司前端JavaScript面试
你需要一些HTML和css的基础知识,掌握JavaScript和ES6的基本语法,对事物的好奇心。
达达前端
2022/04/13
1.7K0
【建议】记录一次BAT一线互联网公司前端JavaScript面试
前端速记
日常记录一些 js/css 相对实用的小笔记,本笔记保持长期更新,如有错误或更好的方案留言反馈
2Broear
2024/03/12
2210
前端速记
2021JavaScript面试题(最新)不定时更新(2021.11.6更新)
js 一共有六种基本数据类型,分别是 Undefined、Null、Boolean、Number、String,还有在 ES6 中新增的 Symbol 类型。 Symbol 代表创建后独一无二且不可变的数据类型,它的出现我认为主要是为了解决可能出现的全局变量冲突的问题。
全栈程序员站长
2022/09/07
2.7K0
JavaScript设置定时器、取消定时器及执行机制解析
今天整理了一下 JavaScript 定时器,顺便了解了一下 JavaScript 的运行机制,现在记录一下。
德顺
2019/11/12
5.1K0
相关推荐
前端 JavaScript 之『节流』的简单代码实现
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档