JavaScript中你不知道的數學方法分享(非常實用)
JavaScript的Math對象包含了一些非常有用和強大的數學操作,可以在Web開發(fā)中使用,但它缺少了許多其他大多數編程語言提供的重要操作(比如Haskell,它具有大量這樣的操作)。
以下是每個操作的快速鏈接:
- Sum
- Product
- Odd and Even
- triangleNumber
- Factorial
- Factors
- isPrime
- Greatest Common Divisor
- Lowest Common Multiple
1.求和(Sum)
你可能還記得在學校中,“sum”是“add”的同義詞。例如,如果我們對數字1、2和3求和,實際上是指1 + 2 + 3。
我們的求和函數將涉及對數組中所有值進行求和。
有兩種編寫這個函數的方式:我們可以使用for循環(huán),或者我們可以使用reduce函數。如果你想重新熟悉reduce函數,你可以閱讀有關在JavaScript中使用map()和reduce()的文檔。
使用for循環(huán)的方式:
function sum(array){ let total = 0 for(let count = 0; count < array.length; count++){ total = total + array[count] } return total }
使用reduce函數的方式:
function sum(array){ return array.reduce((sum, number) => sum + number, 0) }
這兩個函數的工作方式完全相同(reduce函數只是一個內置的for循環(huán)),并且在給定相同數組的情況下將返回相同的結果。但是,reduce函數更加簡潔。
例如:
sum([1,2,3,4]) === 10 // 1 + 2 + 3 + 4 sum([2,4,6,8]) === 20 // 2 + 4 + 6 + 8
能夠對一組數字求和可能是JavaScript Math對象中最有用且最需要的“缺失”數學操作。再次強調,求和函數可以作為一個很好的檢查工具。例如,在數獨游戲中,我們可以通過檢查列或行的總和是否為45(1 + 2 + 3 + 4 +…+ 9)來檢查用戶是否沒有重復的數字。該函數在在線購物應用程序中也非常適用,如果我們想要計算總賬單,假設所有價格都存儲在一個數組中。
以下是在購物應用程序示例中如何使用該函數的示例代碼:
const prices = [2.80, 6.10, 1.50, 1.00, 8.99, 2.99] function totalCost(prices){ return prices.reduce((sum, item) => sum + item, 0) }
2.乘積(Product)
我們的乘積函數將以與求和函數類似的方式工作,不同之處在于,我們將把列表中的所有數字相乘。
同樣地,我們可以幾乎與第一個求和函數一樣使用for循環(huán):
function product(array){ let total = 1 for(let count = 0; count < array.length; count++){ total = total * array[count] } return total }
請注意,我們使用1來初始化total變量,而不是0,否則最后得到的乘積將始終為0。
但是在這種情況下,reduce函數仍然適用,并且仍然是更簡潔的編寫函數的方式:
function product(array){ return array.reduce((total, num) => total*num, 1) }
以下是一些示例代碼:
product([2,5,8,6]) === 480 // 2 x 5 x 8 x 6 product([3,7,10,2]) === 420 // 3 x 7 x 10 x 2
這個函數的用途可能看起來不明顯,但在進行多個轉換的計算時非常有用。例如,如果你想找出十個蘋果包裝袋(每袋一公斤,售價1.50RMB)的美元價格,而不是進行大量的乘法運算,將所有的值存儲在一個數組中并使用剛剛編寫的乘積函數將更加高效。
數組的一個示例格式如下:
const pricePerKg = 1.50 const numberOfKg = 10 const conversionRate = 1.16 const conversion = [1.50, 10, 1.16] const USprice = product([pricePerKg,numberOfKg,conversionRate])
3.奇數和偶數
這些函數將接受一個數字作為參數,可以是數組的長度,根據該數字是奇數還是偶數返回true或false。
要判斷一個數字是否為偶數,它必須能夠被2整除;而要判斷一個數字是否為奇數,則相反,不能被2整除。這將是函數的關鍵部分。
例如,Haskell語言中內置了這些函數,這使得事情變得更加容易,尤其是可以直接編寫如下代碼:
even 29 << false odd 29 << true
另一方面,Ruby提供了這些函數作為方法。這樣編寫起來仍然更加容易:
29.even? << false 29.odd? << true
在JavaScript中,編寫這些函數的最簡單方法是使用取余運算符%。它返回一個數除以另一個數的余數。例如:
11 % 3 === 2 // 11 divide 3 === 3 remainder 2
下面是我們的偶數函數的一個示例:
function even(number){ return number % 2 === 0 }
正如我們所看到的,我們有一個接受數字作為參數的偶數函數,并根據條件返回一個布爾值:
number % 2 === 0
當這個數被2整除時,如果余數等于零,我們就知道它是可以被2整除的,函數將返回true。例如:
even(6) === true even (9) === false
下面是我們的奇數函數的一個示例:
function odd(number){ return number % 2 !== 0 }
這兩個函數非常相似:都接受一個數字作為參數,并根據條件返回一個布爾值:
number % 2 !== 0
如果將數字除以2的余數不等于零,那么這個數就是奇數,函數將返回true。例如:
odd(7) === true odd(114) === false
能夠檢查一個數字是奇數還是偶數非常重要,而且非常簡單。一開始可能并不顯得那么重要,但它可以作為一個很好的輸入驗證技術,例如對于數組長度,或者僅僅通過檢查兩個玩家游戲的勝者來判斷。你可以追蹤已經玩了多少回合,如果回合數是奇數,玩家1獲勝,如果是偶數,玩家2獲勝——假設第一回合計為1。
這兩個函數是可以互換使用的,我們很可能只需要使用其中一個。然而,擁有這兩個函數可以使在代碼中更容易跟蹤真值和假值邏輯,特別是在大塊的代碼中。
下面是我們如何編寫上述示例的代碼:
function checkWinner(gamesPlayed){ let winner if(odd(gamesPlayed)){ winner = "player1" } else{ winner = "player2" } return winner }
4.三角數(Triangle Number)
三角數聽起來比它們實際上要復雜得多。它們只是某個數之前所有整數的和。
例如,這是第五個三角數:5 + 4 + 3 + 2 + 1 = 15。
這與我們之前提到的數獨的例子有關。我們想要檢查所有數字是否唯一,我們可以通過檢查它們是否與1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9的結果相等來實現。這當然就是第九個三角數!
當然,我們可以使用for循環(huán)編寫這個函數,像這樣:
function triangleNumber(number){ let sum = 0 for(let i=1; i < number + 1; i++){ sum = sum + i } return sum }
然而,這將是一個非常低效的決定,因為有一個非常簡單的公式可以計算三角數:0.5 x (number) x (number + 1)。
因此,我們的函數的最高效版本應該是這樣的:
function triangleNumber(number){ return 0.5 * number * (number + 1) }
以下是一些我們如何使用它的示例代碼:
triangleNumber(7) === 28 // 0.5 x 7 x 8 triangleNumber(123) === 7626 // 0.5 x 123 x 124
5.階乘(Factorial)
一個自然數(大于0的任意整數)的階乘是小于等于該數的所有數的乘積。例如:3的階乘(表示為3!)是3 x 2 x 1 = 6。
與求和和乘積函數類似,我們可以用兩種方式創(chuàng)建階乘函數:使用for循環(huán)和使用遞歸。如果你之前沒有接觸過遞歸算法,它們本質上是反復調用自身的函數,直到達到一個“基本情況”。你可以在《函數式JavaScript中的遞歸》中了解更多關于它們的內容。
下面是我們如何使用for循環(huán)創(chuàng)建階乘函數的方法:
function factorial(number){ let total = 1 for (let i = 1; i < number+1; i++){ total = total * i } return total }
該函數通過從1到給定的數字的循環(huán)遍歷(每次遞增)并將總數與每個數字相乘,最后返回最終的總數(即該數字的階乘)。
下面是我們如何使用遞歸創(chuàng)建階乘函數的方法:
function factorial(number){ if (number <= 0){ return 1 } else{ return number * factorial(number - 1) } }
在這個函數中,我們的基本情況是0,因為0的階乘令人驚訝地是1(這個證明實際上非常有趣)。這意味著,當數字通過函數時,只要它不為零,它將乘以factorial(number - 1)。
為了更好地理解函數在每次傳遞時的具體操作,跟蹤算法可能會有所幫助。下面是使用3跟蹤算法的示例:
factorial(3) === 3*factorial(2) === 3*2*factorial(1) === 3*2*1*factorial(0) === 3*2*1*1 === 3*2*1 === 6
無論哪種方式,這兩個函數都會返回相同的值。例如:
factorial(5) === 120 // 5 x 4 x 3 x 2 x 1
6.因子(Factors)
因子是成對出現的,每一對因子相乘得到原始數字。例如:
數字10的因子有:1和10;2和5。
數字18的因子有:1和18;2和9;3和6。
我們希望我們的因子函數接受一個數字,并返回一個包含所有因子的數組。有許多方法可以編寫這個函數,但最簡單的方法是使用命令式的方法,例如這樣:
function factors(number){ let factorsList = [] for(let count = 1; count < number+1; count++){ if(number % count === 0){ factorsList.push(count) } } return factorsList }
首先,我們創(chuàng)建一個數組,初始為空。然后我們使用一個for循環(huán)來遍歷從1到給定數字的每個整數,每次遍歷時我們檢查數字是否可被整數(或在這種情況下的計數器)整除。
如你所見,為了檢查可被整除性,我們再次使用了模運算符。如果數字可被整數整除,則它是一個因子,并可以添加到我們的數組中。
然后返回該數組,每次運行函數時,將返回一個升序排列的因子數組。例如:
factors(50) === [1,2,5,10,25,50]
找出一個數字的因子在許多情況下非常有用,特別是當你需要組織分組時,比如在線游戲中,當你需要每個隊伍都有相等數量的玩家。例如,如果你有20個玩家,每個隊伍需要10個玩家,你可以使用因子函數將10個玩家分配到兩個隊伍中。同樣地,如果每個隊伍需要4個玩家,你可以使用因子函數將4個玩家分配到五個隊伍中。
在實際應用中,可能如下所示:
function createTeams(numberOfPlayers, numberOfTeams){ let playersInEachTeam if(factors(numberOfPlayers).includes(numberOfTeams)){ playersInEachTeam = numberOfPlayers / numberOfTeams } else{ playersInEachTeam = "wait for more players" } return playersInEachTeam }
7.isPrime(是否為素數)
這是學校中最早學到的條件之一,但在日常生活中很少使用。簡而言之,如果一個數有兩個不同的因子,而這兩個因子分別為1和它本身,那么這個數就是素數。素數從2開始:2、3、5、7、11、13、17、19......一直延伸到無窮大。
這個函數可能一開始看起來很復雜,但如果我們剛剛寫過一個非常有用的因子函數,它實際上會變得非常簡單。如前所述,如果一個數有兩個不同的因子,那么它就是素數,因此我們的函數可以簡單地寫為:
function isPrime(number){ return factors(number).length === 2 }
該函數將根據因子列表的長度是否為2返回一個布爾值,換句話說,它將返回該數字是否有兩個因子。
實際應用時,它會像這樣:
isPrime(3) === true isPrime(76) === false isPrime(57) === true
在上面的“分組用戶”示例中繼續(xù),如果用戶數量是素數,我們無法平均分組(除非我們只有一個組,但這會違背示例的目的),這意味著我們必須等待另一個用戶加入。因此,我們可以在這樣的函數中使用它:
function addUsers(users){ if(isPrime(users)){ wait = true } else{ wait = false } }
8.gcd(最大公約數)
有時被稱為“最高公因數”,最大公約數操作找到兩個數共有的最大因數。
例如:
12和15的最大公約數是3
8和4的最大公約數是4。
一種簡單的方法是列出每個數的所有因數(使用上面提到的令人難以置信的函數),然后比較這些列表。然而,比較這些列表需要一些巧妙但也不太高效的數組操作。
不過,下面仍然是一個示例:
function gcd(number1, number2){ let inCommon = [] for(let i of factors(number1)){ if(factors(number2).includes(i)){ inCommon.push(i) } } return inCommon.sort((a,b)=> b - a)[0] }
這里,我們將一個空數組賦給變量inCommon,并循環(huán)遍歷number1的因數數組(使用之前的函數)。如果number2的因數數組包含當前遍歷的項,我們將其推入inCommon數組中。
一旦我們獲得了兩個數共有的因數數組,我們返回數組中按降序排序的第一個值。換句話說,我們返回最大公約數。
可以想象,如果我們沒有之前創(chuàng)建的factors函數,這個代碼會很龐大。
一種更簡潔但更難的方法是使用遞歸。這是一個相當著名的算法,被稱為歐幾里得算法:
function gcd(number1, number2){ if(number2 === 0){ return number1 } else{ return gcd(number2, number1%number2) } }
我們的基本情況是當number2等于0時,此時number1就是最大公約數。否則,最大公約數是number2和number1除以number2的余數的最大公約數。
同樣,這兩個函數都會返回相同的結果。例如:
gcd(24, 16) === 8 gcd(75, 1) === 1
最小公倍數(LCM)是找出兩個或多個數能夠整除的最小的正整數。
例如:
2和6的最小公倍數是6。 4和15的最小公倍數是60。 不幸的是,我們不能簡單地列舉出每個數的所有倍數,因為這將是一個無限列表。
然而,我們可以使用一個非常有用的公式來計算最小公倍數:
(number1 x number2) / the Greatest Common Divisor of the two numbers
使用公式計算2和6的最小公倍數(LCM)的步驟如下:
- 找到兩個數的最大公約數(GCD)。在這種情況下,2和6的最大公約數是2。
- 將兩個數相乘并除以它們的最大公約數。在這種情況下,2乘以6除以2等于6。
因此,2和6的最小公倍數(LCM)是6。
(2 x 6)/gcd(2,6) = 12/2 = 6
幸運的是,我們剛剛創(chuàng)建了一個gcd函數,因此創(chuàng)建lcm函數非常容易:
function lcm(number1, number2){ return (number1*number2)/gcd(number1, number2) }
就這樣!我們只需要返回上面的公式,它應該可以正常工作:
lcm(12, 9) === 36 // (12 x 9)/3
這個函數可能沒有明顯的實際用途,但在兩個事件以不同的間隔發(fā)生時,我經常發(fā)現它非常有用。這意味著我們可以使用最小公倍數(LCM)來找出兩個事件同時發(fā)生的時間。
例如,如果一個圖像被設置為每隔六秒出現一次,而一個段落的文本被設置為每隔八秒出現一次,那么在第24秒時,圖像和段落將首次同時出現。
以上就是JavaScript中你不知道的數學方法分享(非常實用)的詳細內容,更多關于JavaScript數學方法的資料請關注腳本之家其它相關文章!
相關文章
微信小程序webview組件交互,內聯h5頁面并網頁實現微信支付實現解析
這篇文章主要介紹了小程序webview組件交互,內聯h5頁面并網頁實現微信支付實現解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-08-08