為什么 Math.min() 比 Math.max() 大?
考慮如下代碼:
- var min = Math.min();
- var max = Math.max();
- console.log(min < max);
按照常規(guī)思路,這段代碼應(yīng)該輸出 true,畢竟最小值應(yīng)該小于***值。但是當(dāng)我們運(yùn)行這段代碼時(shí),卻神奇的輸出了 false。
為什么會(huì)這樣呢?
還得去查查 MDN 的相關(guān)文檔。
The Math.min() function returns the smallest of zero or more numbers.
Math.min 的參數(shù)是 0 個(gè)或者多個(gè)。如果是多個(gè)參數(shù)很容易理解,返回參數(shù)中最小的。
如果是 0 個(gè)參數(shù)呢?文檔中寫(xiě)到:
If no arguments are given, the result is Infinity.
If at least one of arguments cannot be converted to a number, theresult is NaN.
如果沒(méi)有參數(shù),則返回 Infinity。Infinity 是什么呢?Infinity 是 javascript 中全局對(duì)象的一個(gè)屬性,在瀏覽器環(huán)境中就是window 對(duì)象的一個(gè)屬性,表示無(wú)窮大。
而 Math.max() 沒(méi)有傳遞參數(shù)時(shí)返回的是 -Infinity。因此 Math.min() 要比 Math.max() 大。
后續(xù):
為什么很多人會(huì)有這種疑惑,是因?yàn)榉噶讼氘?dāng)然的錯(cuò)誤——望文生義。Math.min() 作為一個(gè)函數(shù),返回的并不是最小值;同理 Math.max() 返回的也不是***值。他們返回的是參數(shù)的***值和最小值,而我們卻沒(méi)有傳遞任何參數(shù)。
javascript 中數(shù)值的***值和最小值常量分別是 Number.MAX_VALUE 和 Number.MIN_VALUE,在我電腦 V8 的運(yùn)行結(jié)果是 1.7976931348623157e+308 和 5e-324。
這里也有一個(gè)坑,那就是 MIN_VALUE 并不是最小的數(shù),而是絕對(duì)值最小的數(shù),它是一個(gè)正數(shù)。而 Math.min() 的返回值比 Number.MAX_VALUE 還要大。
Math.min() 返回了 Infinity,這個(gè)值對(duì)應(yīng)了 Number.POSITIVE_INFINITY 常量。Math.max() 返回了 -Infinity,這個(gè)值對(duì)應(yīng)了 Number.NEGATIVE_INFINITY 常量。
就像數(shù)學(xué)里面那樣,正無(wú)窮和負(fù)無(wú)窮并不是確切的數(shù),只是集合里面的概念。我們可以使用 0 減去正無(wú)窮來(lái)得到負(fù)無(wú)窮:0 - Infinity = -Infinity,或者通過(guò) 0 減去負(fù)無(wú)窮來(lái)得到正無(wú)窮:0 - (-Infinity) = Infinity。但是我們把正無(wú)窮和負(fù)無(wú)窮相加卻得不到 0,事實(shí)上我們得到的是 NaN。
當(dāng)我們真正明白了 Math.min 和 Math.max 只是返回了所有參數(shù)的***值,就很容易理解這個(gè)看似匪夷所思的結(jié)果了。
本來(lái)想查看 V8 的源碼,但是搜索了一圈,也只找到了幾個(gè)測(cè)試用例(文件: test/mjsunit/math-min-max.js):
- assertEquals(Infinity, Math.min());
- assertEquals(1, Math.min(1));
- assertEquals(1, Math.min(1, 2));
- assertEquals(1, Math.min(2, 1));
- assertEquals(1, Math.min(1, 2, 3));
- assertEquals(1, Math.min(3, 2, 1));
- assertEquals(1, Math.min(2, 3, 1));
從此測(cè)試用例中可以看出,Math.min() 確實(shí)返回了 Infinity。繼續(xù)閱讀此測(cè)試用例還會(huì)發(fā)現(xiàn)更有意思的事:
- assertEquals(-Infinity, Infinity / Math.min(-0, +0));
- assertEquals(-Infinity, Infinity / Math.min(+0, -0));
- assertEquals(-Infinity, Infinity / Math.min(+0, -0, 1));
對(duì)比下面的結(jié)果:
- assertEquals(Infinity, Infinity / Math.max(-0, +0));
- assertEquals(Infinity, Infinity / Math.max(+0, -0));
- assertEquals(Infinity, Infinity / Math.max(+0, -0, -1));
也就是說(shuō)在 Math.min 和 Math.max 進(jìn)行數(shù)值比較(javascript不分整型和浮點(diǎn)型)時(shí),負(fù)零是小于正零的。
-0、+0、-Infinity、+Infinity、NaN 這幾個(gè)概念就可以講上一天一夜了,篇幅有限就不展開(kāi)講了,以后有時(shí)間再填坑。
言歸正傳,現(xiàn)在我們換個(gè)思路,試著從算法的角度去考慮***值和最小值的問(wèn)題。
我們?nèi)绾吻?N 個(gè)參數(shù)的***值呢?為了描述簡(jiǎn)單我們使用數(shù)組(感謝 @f2er前端百科)
- var max = ___;
- arr.forEach(function(n) {
- if(n > max) {
- max = n;
- }
- });
如果是填空題,你會(huì)在空格處填什么呢?如此想來(lái),這個(gè)返回值就很合理了。
--------------------------------
<del>本來(lái)以為是無(wú)參調(diào)用時(shí)返回了運(yùn)算的幺元,后來(lái)細(xì)琢磨,好像沒(méi)有什么關(guān)系,2333
對(duì)于運(yùn)算集合 S 上的二元運(yùn)算*,如果滿足 a*x = x*a = x,則 a 是*運(yùn)算的幺元。加法運(yùn)算的幺元是 0,因?yàn)?0+x = x+0 = x。乘法運(yùn)算的幺元是 1,因?yàn)?1*x = x*1 = x。但是我們定義函數(shù) add() 或者 mult() 函數(shù),如果不傳遞參數(shù)時(shí),返回幺元的話也是不合理的。</del>