资讯专栏INFORMATION COLUMN

前端碎语(3)

Brenner / 1944人阅读

摘要:而写成还可以满足你获得回调函数返回值的需求。而构建函数表达式的方法也不止把声明括起来这种,一些其他的操作符也可以,比如赋值号到目前为止,我们似乎能够得出结论函数声明后不可直接跟圆括号,而函数表达式后面可以。

使用setTimeout替代setInterval

setInterval()这个间歇调用函数是应用得比较广的,尤其在比较古老的浏览器中实现动画效果时,往往离不开它。然而这个函数却有不少坑,由于其实现是把要执行的代码插入待执行队列排队执行,同时为防止连续执行,这个队列中只能有一个最早进来的它的代码实例。如果队列中也有其他任务在等待,而且执行了很长时间,首先就很容易导致计时不准;再者,还会打乱其执行的时间线,导致setInterval()迟迟不能再添加新的代码实例,最终出现略过某次执行的现象等问题,如下图所示:

如果你要获取每次间歇执行的结果,那就要避免setInterval()可能略过某次执行缺点,可以用setTimeout()改写它:

    //原函数
    var intervalId = setInterval(function () {
        if(someCondition) {
            clearInterval(intervalId);
            console.log("done");
            }
        }, 1000);

    //改写后
    function fun() {
        if(someCondition) {
                console.log("done");
            } else 
            {
                setTimeout(fun, 1000);
            }
    }

    setTimeout(fun, 1000);

虽然setTimeout()的计时也未必很准确,但由于上述代码是链式使用的,一环扣一环,从源头阻止了略过某次执行的情况。同时使用setTimeout()也更灵活些、定制性更强,想执行到某个周期就停下来,只要你不继续调用就可以了,没必要专门再加个clearTimeout()。最后,既然是链式执行,那你第一个调用可用普通的函数调用即可,然后在执行时自然会调用setTimeout(),而不用像setInterval()那样第一个调用也必须等待一段时间,这样可以满足一些更细致的要求。

如何给setTimeout()的回调函数传参?

这个问题其实也代表了一类问题,即如何在如setTimeout()setInterval()、指定DOM事件等限制使用函数引用而非函数调用的场合,仍然能给将来要调用的函数传递参数。

为什么要给函数传参?因为传参和返回值一样,是函数作为子程序与外界通信的一大手段。但在上面提到那些限制必须使用函数引用的场景下,如果我们只用函数的引用而没有调用函数,那就意味着不能给直接给它传参、也不能接受它的返回值,这就使得子程序间的数据通信少了一大功能,此时,你要让回调函数与外界通信貌似也就只有通过全局变量了。

但深入想一想,这些场景只是规定要用到函数引用,并没有说一定是回调函数的引用,那也意味着我们可以偷梁换柱,用别的函数引用来“占着”本来应该是回调函数引用的位置,而让回调函数进行调用。于是我们就有了解决方法,以setTimeout()为例最简单的一种想法如下:

    setTimeout(function() {
        callback(arg);
    }, timeout);

这里用到一个匿名函数作为第一个参数,匿名函数提供了它的函数引用后,回调函数就可以在匿名函数体内直接调用、传参了。而写成return callback(arg)还可以满足你获得回调函数返回值的需求。

除了外套匿名函数这种方法,我们还可以使用功能更加强大的闭包,来解决这个传参问题:

    setTimeout((function(arg) {
        return function () {
            callback(arg);
        };
    })(arg), timeout);

其实就是在第一种方法的基础上再外套一个立即执行表达式,这个闭包实际上是包含了传参操作的,但有了它我们就可以来解决那些我们通过构造闭包可以解决的的问题了。比如获取某次循环等更具体的块级作用域中的变量值:

for (i in Arr) {
    setTimeout((function(arg) {
        return function () {
            callback(arg);
        };
    })(i), timeout);
}
函数声明和函数表达式

在使用立即执行表达式(IIFE)时,我们常采用(function () {})()这种形式,若去掉第一组括号直接在函数声明后面加括号则会报错:

    function () {}() //Uncaught SyntaxError: Unexpected token (

显然js的函数声明后面是不能直接加括号让它立即执行的,但我们把函数声明括起来,立即执行的就不是一个函数,而是一个所谓函数表达式了。而构建函数表达式的方法也不止把声明括起来这种,一些其他的操作符也可以,比如赋值号:

    var A = function () {}();

到目前为止,我们似乎能够得出结论:函数声明后不可直接跟圆括号,而函数表达式后面可以。然而js认为什么是函数声明、什么是函数表达式却并不是简单靠函数声明的外在形式来决定的,比如下面这个例子:

    function A(i){
        console.log(i);
    }

    A(function () {
        return 5;
    }()); //5

上面的代码里A函数的参数直接在函数声明后面加上了括号,看起来是个非法的IIFE了,而这个“非法”IIFE作为参数时却能正常地立即执行。但再仔细想想,我们知道传参的过程其实是相当于赋值的,所以这种传参形式其实和上面提到的通过赋值号构建函数表达式应该是一个道理,立即执行的其实还是是函数表达式,而非函数声明,不要被表像迷惑了。

而为防止以后读代码时再踩坑,我想出了个更简单的区分两者的“方法”:只要function不是放在一个语句最前面时就可以连同后面的声明内容当作函数表达式,就可以加括号立即执行。

当然在写代码用到IIFE时,就没必要纠结这些降低效率了,直接在声明外括括号得了,这样既写起来方便又看起来简洁明了。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78760.html

相关文章

  • 前端碎语(5)

    摘要:禁止用户选择文字在一些应用场合,我们不希望用户能够选择文字。在下使用透明效果虽然已经停止对的技术支持了,然而做前端的还得被它恶心一段时间,有些兼容性的问题是我们仍要面对滴。但是,前端界被虐了这么多年,解决问题的方法总是有的。 禁止用户选择文字 在一些应用场合,我们不希望用户能够选择文字。比如在拖动交互中,如果用户能选择元素内部的文字,也就意味着能拖动它们,这样就会干扰对元素的拖动、影响...

    xiaoqibTn 评论0 收藏0
  • 前端碎语(5)

    摘要:禁止用户选择文字在一些应用场合,我们不希望用户能够选择文字。在下使用透明效果虽然已经停止对的技术支持了,然而做前端的还得被它恶心一段时间,有些兼容性的问题是我们仍要面对滴。但是,前端界被虐了这么多年,解决问题的方法总是有的。 禁止用户选择文字 在一些应用场合,我们不希望用户能够选择文字。比如在拖动交互中,如果用户能选择元素内部的文字,也就意味着能拖动它们,这样就会干扰对元素的拖动、影响...

    xialong 评论0 收藏0
  • 前端碎语(6)

    摘要:和属性数值对应的是元素的内容加所占据的视觉面积,有滚动条时还要加上滚动条,不含。和仍要分有没有滚动,有滚动时指的是整个页面内容的大小没滚动时在下指视口的大小和下则是和一样。与属性在下都和原来一样指整个元素的可视宽高。 光标效果不见了? 在页面里,屏幕上光标的样式我们可以用css的cursor属性进行定义。一般来讲,只要光标hover到指定的元素上面其样式就会按我们指定的进行显示,但是如...

    Youngs 评论0 收藏0
  • 前端碎语(6)

    摘要:和属性数值对应的是元素的内容加所占据的视觉面积,有滚动条时还要加上滚动条,不含。和仍要分有没有滚动,有滚动时指的是整个页面内容的大小没滚动时在下指视口的大小和下则是和一样。与属性在下都和原来一样指整个元素的可视宽高。 光标效果不见了? 在页面里,屏幕上光标的样式我们可以用css的cursor属性进行定义。一般来讲,只要光标hover到指定的元素上面其样式就会按我们指定的进行显示,但是如...

    edagarli 评论0 收藏0
  • 前端碎语(4)

    摘要:键盘事件与文本框变化的过程键盘事件最基本的应用场合是控制文本框元素,而我们要讨论的,就是几个键盘事件发生的时机与文本输入的过程的关系。可以看到,除了外,事件并不会输出刚按下的字符,说明他们在文本框变化之前发生而在之后发生。 键盘事件与文本框变化的过程 键盘事件最基本的应用场合是控制文本框元素,而我们要讨论的,就是几个键盘事件:keydown、keypress、keyup、textInp...

    zhiwei 评论0 收藏0

发表评论

0条评论

Brenner

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<