欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JS: 一个小例子引发的思考

程序员文章站 2022-07-13 11:03:30
...

一个小例子引发的思考

emmmm……

最近在看一个开源库,看其中的栗子中发现了一段很有意思的代码。栗子简化一下是下面的这个样子的:

function a() { console.log('a'); setTimeout(b); }
function b() { console.log('b') }
function c() { console.log('c') };

a(c());

可能你觉得这没什么,不就几个简单的方法调用么,有什么复杂的?那么我们先来看一下在Chrome的控制台里面会输出什么?

JS: 一个小例子引发的思考

可能的确如你所料,控制台依次输出了c、a、b(虽然有个不知道什么鬼的undefined,这个等下再说),那说明你对JS中函数的执行顺序有一定的了解。的确,前面声明了三个方法,a,b,c,然后加上括号使a成为语句执行。但是a(c())这种写法怪怪的,内部怎么执行的?还有这个输出怎么会有一个undefined(面试题埋坑啊)?

我同样也有这样的疑问,那么深究之前,先整理一下我们的疑问。

这段代码的输出是什么?a(c())这种写法是什么鬼?undefined是什么鬼?setTimeout不写时间参数会咋样?会有浏览器差异么?

那么我们一个个的来为我们疑问来寻找答案……

这段代码的输出是什么?为什么会有这样子的输出?

其实答案已经看到了,就是c、a、b。因为JS是单线程执行的,所以在执行a方法的过程中,先执行了()中的语句,也就是c()方法,所以顺序执行也就是c、a、b。

emmm……说了和没说一样,没关系往下看。

a(c())这种写法是什么鬼?

接着上个答案的来说。要明白a(c())这种写法是什么鬼?我们得先了解在JS中()是个什么作用?对于普通的语句,()直接执行。对于函数来说,JavaScript解释器会在默认的情况下把遇到的function关键字当作是函数声明语句(statement)来进行解释的。先来看下面的这几个栗子:

(111)   // 常量,当做语句处理。打印 111

(var a)  // 变量声明。 报错

(a = 1)  // 赋值语句,不要写';'。打印 1

function(){console.log('aa')}()  // 匿名函数,不是标准的函数声明语句。报错

(function(){console.log('aa')}())  // 立即执行函数。打印 aa

(function(){console.log('aa')})()  // 立即执行函数。打印 aa

所以其实大致的意思已经很明了。 通俗的来讲就是 因为c首先是一个很标准的函数语句,然后()又可以执行语句,所以a(c())的执行顺序就是先执行了c方法,然后继续执行a方法。如果换成下面的这种方式c就不会执行了:

a(c());   // c、a、b

a(c);   // a、b

a(function(){console.log('nini')}); // a、b

好像也没有那么绕……

undefined是什么鬼?

基本路子搞明白了,那么这个undefined是什么鬼?其实很简单,这是Chrome控制台的一种默认机制,对于执行语句来说,控制台会默认去拿上一行语句的输出。

a = 1;  // 打印 1

var a = 1; // 打印 undefined, 因为这是两行语句

(function(){return 1;})() // 打印 1

function a() {} a(); // 打印 undefined

function a() { return 11; } a(); // 打印 1

所以打印undefined的问题找到了,那么问题来了,node中会不会打印呢?尝试了一波儿发现,node中并不会打印,所以同样是V8引擎,但是控制台这一块儿还是有差距的。

setTimeout不写时间参数会咋样?

终于碰到了最喜欢的setTimeout方法。查阅一堆乱七八糟资料后,setTimeout不写时间参数的话,会由浏览器默认给加上延迟参数,具体多少各家浏览器都不一样。

emmm……无所谓了,那么 setTimeout(func,0) 和 setTimeout(func) 有什么区别么?

下面两张图是在控制台进行了4次的对比试验。

没有时间参数

JS: 一个小例子引发的思考

时间参数为0

JS: 一个小例子引发的思考

好像加上0的确会快一些。不过我们也知道,即使是0,setTimeout 的作用也只是加到当前执行的事件队列当中,而且在浏览器端每次执行也会有4ms的延迟。具体的可以看一看我的另一篇: 看了这么久JS,事件队列你真的懂吗?

关于浏览器的4ms的差异延迟,我们暂时不用在意。当我们需要遇到性能瓶颈时可以去研究一下,具体的方案的实现还都挺有意思的。

会有浏览器差异么?

有,不过控制台的输出影响不大。不必在意。

结尾

以上,基本上该思考的都思考了,不知道你看到这里,还有什么在思考的,倘若有的话,不妨说来听听。