Math.random()是有副作用的函数吗
发布于 6 年前 作者 dislido 3062 次浏览 来自 问答

chrome 68提供了一个便利的新功能:Eager Evaluation 它可以让你在控制台输入一段代码后,无需回车运行即可看到执行结果(实际上是在你输入完后它会自动执行并显示结果) image.png 显然,那些会改变外部变量(有副作用)的表达式不能使用这个功能(比如let a = 1; a++就不会显示a++的结果2)

DevTools does not eager evaluate if the expression causes side effects

几天前我无意中发现Math.random()也能使用Eager Evaluation,这产生了一个神奇的结果,效果如下图
v2-3a281a95f43b433ab4b4b0bffc48463d_b.gif 一般来说,生成随机数会改变seed的值,因此random应该属于有副作用的函数,但是Eager Evaluation为什么会判断它是无副作用的呢?

我做了以下几个猜测:

  • JS的Math.random()不能设置种子,它只能产生一个0-1的随机数,也就是说在js的环境中它没有(不需要)改变任何的变量,只是在v8中改变了seed,Eager Evaluation的实现是只要在js环境中无副作用就能触发
  • 虽然它改变了seed,但因为Math.random()是唯一能够影响这个值的方式,且seed不能被指定初始值,所以Eager Evaluation单独标记了Math.random()为纯函数
  • 单纯是chrome的bug(应该不可能)
1 回复

之前V8的4.x分支是没有种子,在5.x以及后面的分支版本都是有种子,目前v8的master分支默认就是在win下是用rand_s来做种,在其他环境下则是用/dev/urandom文件来做种。以目前的默认方式来看应该是且seed不能被指定初始值,道理上是第二条猜测。但我觉得实际上通过缓存还是能实现Eager Evaluation保持一致,估计是他们还没做到这步吧。 目前最新的node可以直接用–random-seed来指定种子(如我设置种子等于123),如下

node --random-seed=123

而且ECMA要求也简单,所以不同的浏览器,它可以想用什么算法都可以用,只要均匀就好

Returns a Number value with positive sign, greater than or equal to 0 but less than 1, chosen randomly or pseudo randomly with approximately uniform distribution over that range, using an implementation-dependent algorithm or strategy. This function takes no arguments.

回到顶部