开篇语

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

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

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

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

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

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

惑起

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

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

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

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

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

解惑

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

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

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

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

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

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

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

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

改错

既然知道问题出在哪,那就好办了,我们只需要将 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

~

~
本文完,感谢阅读!

~

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

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

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

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

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

  1. 终于搞懂了vue 的 render 函数(一) -_-|||

    终于搞懂了vue 的 render 函数(一) -_-|||:https://blog.csdn.net/sansan_7957/article/details/83014838 render: h ...

  2. [转]我花了一个五一终于搞懂了OpenLDAP

    轻型目录访问协议(英文:Lightweight Directory Access Protocol,缩写:LDAP)是一个开放的,中立的,工业标准的应用协议,通过IP协议提供访问控制和维护分布式信息的 ...

  3. 探索JAVA并发 - 终于搞懂了sleep/wait/notify/notifyAll

    > sleep/wait/notify/notifyAll分别有什么作用?它们的区别是什么?wait时为什么要放在循环里而不能直接用if? ## 简介 首先对几个相关的方法做个简单解释,Obje ...

  4. 终于搞懂了PR曲线

    PR(Precision Recall)曲线 问题 最近项目中遇到一个比较有意思的问题, 如下所示为: 图中的PR曲线很奇怪, 左边从1突然变到0. PR源码分析 为了搞清楚这个问题, 对源码进行了分 ...

  5. hdu1711(终于搞懂了KMP算法了。。)

    题意:给你两个长度分别为n(1 <= N <= 1000000)和m(1 <= M <= 10000)的序列a[]和b[],求b[]序列在a[]序列中出现的首位置.如果没有请输 ...

  6. Lua的闭包详解(终于搞懂了)

    词法定界:当一个函数内嵌套另一个函数的时候,内函数可以访问外部函数的局部变量,这种特征叫做词法定界 table.sort(names,functin (n1,n2) return grades[n1] ...

  7. 终于搞懂了shell bash cmd...

    问题一:DOS与windows中cmd区别 在windows系统中,“开始-运行-cmd”可以打开“cmd.exe”,进行命令行操作. 操作系统可以分成核心(kernel)和Shell(外壳)两部分, ...

  8. IntelliJ IDEA 部署 Web 项目,终于搞懂了!

    这篇牛逼: IDEA 中最重要的各种设置项,就是这个 Project Structre 了,关乎你的项目运行,缺胳膊少腿都不行. 最近公司正好也是用之前自己比较熟悉的IDEA而不是Eclipse,为了 ...

  9. 终于搞懂Spring中Scope为Request和Session的Bean了

    之前只是很模糊的知道其意思,在request scope中,每个request创建一个新的bean,在session scope中,同一session中的bean都是一样的 但是不知道怎么用代码去验证 ...

随机推荐

  1. axios提交表单

    后端使用@RequestBody接收jsons数据 因为后端接收json数据,所以前端也要发送json 项目的前端是使用layui的数据表单 案例方法 方法一:JSON字符串 提交的数据格式 {&qu ...

  2. 【.Net Core】分析.net core在linux下内存占用过高问题

    现象 随着程序运行,内存占用率越来越高,直到触发linux的OOM,程序被杀死. 分析工具 运行环境:.net core 3.1(微软的分析工具要求最低3.0,无法分析2.1的core程序,需要先改为 ...

  3. 2020.12.20vj补题

    A - Insomnia cure 题意:一共s只龙,每隔k,l,m,n只龙就会受伤,问这s只龙有多少龙是受伤的 思路:看起来题目范围并不是很多,直接进行循环判断 代码: 1 #include< ...

  4. Codeforces Beta Round #73(Div2)

    A - Chord 题意:就是环中有12个字符,给你三个字符,判断他们之间的间隔,如果第一个和第二个间隔是3并且第二个和第三个间隔是4,那么就输出minor,如果第一个和第二个间隔是4并且第二个和第三 ...

  5. [Java] 数据分析 -- NoSQL数据库

    MongoDB概念:与关系型数据库对应 database(数据库):数据库 collection(集合):表 document(文档):行 field(域):列/字段 注意事项 文档是一组键值(key ...

  6. Jmeter 设置中文

    1.正常启动jmeter.bat 2.点击[Options]选项,弹出下拉菜单选择[Choose Language]选项3.选择[Choose Language]选项,弹出下一级菜单选择[Chines ...

  7. [转载]有些shell文件中为啥要用$(cd “$(dirname $0)“; pwd),pwd它不香吗

    $(cd "$(dirname "$0")",pwd) 解析   xx.sh 文件内容如下: #!/bin/bash BIN_FOLDER=$(cd " ...

  8. liveCD版: CD光盘映像,和liveDVD一样,唯一的区别就是该版本中包含的软件包会少一点,安装系统时使用 U 盘或者CD光盘进行安装。

    https://man.linuxde.net/download/CentOS/ CentOS,英文全称"Community Enterprise Operating System" ...

  9. IT菜鸟之OSI七层模型

    OSI七层模型从下到上分别是: 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 第一层物理层: 物理层是传输媒介(网线.无线.光纤) 在线路中起到的作用:是将0/1转换成电信号或光信号 物 ...

  10. jmeter从安装到使用

    最近,项目需要做接口测试,在python和jmeter之前选择,最终还是选择jmeter,虽然脚本管理及持续集成方面有所不便,但胜在使用简单,调试方便,方便后续做并发压力测试,而且最后的报告统计图表也 ...