• (鸡汤文)搞懂了 JavaScript 定时器 setTimeout() 的 this 指向!


    开篇语

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

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

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

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

    宝藏女孩

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

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

    惑起

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

    <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 += `
    ${ 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

    出处:https://www.cnblogs.com/bianchengsanmei/p/14908638.html

    您的资助是我最大的动力!
    金额随意,欢迎来赏!
    款后有任何问题请给我留言。

    如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的推荐按钮。
    如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的关注我。(●'◡'●)

    如果你觉得本篇文章对你有所帮助,请给予我更多的鼓励,求打             付款后有任何问题请给我留言!!!

    因为,我的写作热情也离不开您的肯定支持,感谢您的阅读,我是【Jack_孟】!

  • 相关阅读:
    14071702(SkeletalControl_Limb)
    14072202(带IK的Recoil)
    UE3植被工具-支持刷Actor)
    UDK:AdventureKit 攀爬系统
    16082402(SkeletalMesh的绘制流程)
    windows下安装nodejs
    laravel迁移文件
    laravel的资源路由resource
    sleep参数是整型还是小数
    node.js和npm的关系
  • 原文地址:https://www.cnblogs.com/mq0036/p/14911481.html
Copyright © 2020-2023  润新知