- A+
所属分类:Web前端
在一个被广为流传的 JavaScript Meme(梗图)中,我们可以看到这么一个例子,Math.max()
在不填入的参数的情况下返回了 -INFINITY
,Math.min()
在同样的情况下返回了 INFINITY
。
明明是一个求最大数的方法,却返回了用于表示最小数的 -INFINITY
,这让我感觉到有点匪夷所思。
想探寻为什么其实很简单,标准库的代码其实也是人写的,只要去找一下 Math.max()
与 Math.min()
的具体实现方式就能知道了。
以下文字内容建议配合附加的代码配合观看
以 Math.max()
为例,在 Chrome 浏览器所使用的 JavaScript 引擎,也就是 V8 引擎的 Math 库的源码中,我们可以看到当所填入的参数个数为 2
时,则使用 if
语句既可以实现返回最大值的功能。但当填入的参数个数不为 2
时,则是使用 for
循环遍历所有的参数,并使用一个变量 r
存储参数中最小的值。而变量 r
的在一开始被赋值为 -INFINITY
,如果参数的个数为 0
时,则用于找出最小值的 for
语句块则不会被执行,所以直接返回了 -Infinity
。
Math.min()
其实也是一个思路,这里就不多讲了。
// ECMA 262 - 15.8.2.11 function MathMax(arg1, arg2) { // length == 2 var length = %_ArgumentsLength(); // 如果参数的个数为2,直接使用if语句判断结果 if (length == 2) { arg1 = TO_NUMBER_INLINE(arg1); arg2 = TO_NUMBER_INLINE(arg2); if (arg2 > arg1) return arg2; if (arg1 > arg2) return arg1; if (arg1 == arg2) { // 如果两个参数都为0(如参数填入了0与-0),优先返回-0 // Make sure -0 is considered less than +0. return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg2 : arg1; } // All comparisons failed, one of the arguments must be NaN. return NAN; } // 如果参数的个数不为2,比如填入了0个、1个甚至多个参数时 // 通过遍历的方式找出最小值,并用变量r进行存储 var r = -INFINITY; // 如果参数个数为0,这下面的for语句块则不会执行 for (var i = 0; i < length; i++) { var n = %_Arguments(i); if (!IS_NUMBER(n)) n = NonNumberToNumber(n); // Make sure +0 is considered greater than -0. if (NUMBER_IS_NAN(n) || n > r || (r === 0 && n === 0 && %_IsMinusZero(r))) { r = n; } } return r; } // ECMA 262 - 15.8.2.12 function MathMin(arg1, arg2) { // length == 2 var length = %_ArgumentsLength(); if (length == 2) { arg1 = TO_NUMBER_INLINE(arg1); arg2 = TO_NUMBER_INLINE(arg2); if (arg2 > arg1) return arg1; if (arg1 > arg2) return arg2; if (arg1 == arg2) { // Make sure -0 is considered less than +0. return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg1 : arg2; } // All comparisons failed, one of the arguments must be NaN. return NAN; } var r = INFINITY; for (var i = 0; i < length; i++) { var n = %_Arguments(i); if (!IS_NUMBER(n)) n = NonNumberToNumber(n); // Make sure -0 is considered less than +0. if (NUMBER_IS_NAN(n) || n < r || (r === 0 && n === 0 && %_IsMinusZero(n))) { r = n; } } return r; }