本文目錄一覽:
number-precision 實現js高精度運算 源碼
type numType = number | string;
/**
* @desc 解決浮動運算問題,避免小數點後產生多位數和計算精度損失。
* 問題示例:2.3 + 2.4 = 4.699999999999999,1.0 – 0.9 = 0.09999999999999998
*/
/**
* 把錯誤的數據轉正
* strip(0.09999999999999998)=0.1
*/
function strip(num: numType, precision = 15): number {
return +parseFloat(Number(num).toPrecision(precision));
}
/**
* Return digits length of a number
* @param {*number} num Input number
*/
function digitLength(num: numType): number {
// Get digit length of e
const eSplit = num.toString().split(/[eE]/);
const len = (eSplit[0].split(‘.’)[1] || ”).length – +(eSplit[1] || 0);
return len 0 ? len : 0;
}
/**
* 把小數轉成整數,支持科學計數法。如果是小數則放大成整數
* @param {*number} num 輸入數
*/
function float2Fixed(num: numType): number {
if (num.toString().indexOf(‘e’) === -1) {
return Number(num.toString().replace(‘.’, ”));
}
const dLen = digitLength(num);
return dLen 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num);
}
/**
* 檢測數字是否越界,如果越界給出提示
* @param {*number} num 輸入數
*/
function checkBoundary(num: number) {
if (_boundaryCheckingState) {
if (num Number.MAX_SAFE_INTEGER || num Number.MIN_SAFE_INTEGER) {
console.warn(`${num} is beyond boundary when transfer to integer, the results may not be accurate`);
}
}
}
/**
* 精確乘法
*/
function times(num1: numType, num2: numType, …others: numType[]): number {
if (others.length 0) {
return times(times(num1, num2), others[0], …others.slice(1));
}
const num1Changed = float2Fixed(num1);
const num2Changed = float2Fixed(num2);
const baseNum = digitLength(num1) + digitLength(num2);
const leftValue = num1Changed * num2Changed;
checkBoundary(leftValue);
return leftValue / Math.pow(10, baseNum);
}
/**
* 精確加法
*/
function plus(num1: numType, num2: numType, …others: numType[]): number {
if (others.length 0) {
return plus(plus(num1, num2), others[0], …others.slice(1));
}
const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
}
/**
* 精確減法
*/
function minus(num1: numType, num2: numType, …others: numType[]): number {
if (others.length 0) {
return minus(minus(num1, num2), others[0], …others.slice(1));
}
const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
return (times(num1, baseNum) – times(num2, baseNum)) / baseNum;
}
/**
* 精確除法
*/
function divide(num1: numType, num2: numType, …others: numType[]): number {
if (others.length 0) {
return divide(divide(num1, num2), others[0], …others.slice(1));
}
const num1Changed = float2Fixed(num1);
const num2Changed = float2Fixed(num2);
checkBoundary(num1Changed);
checkBoundary(num2Changed);
// fix: 類似 10 ** -4 為 0.00009999999999999999,strip 修正
return times(num1Changed / num2Changed, strip(Math.pow(10, digitLength(num2) – digitLength(num1))));
}
/**
* 四捨五入
*/
function round(num: numType, ratio: number): number {
const base = Math.pow(10, ratio);
return divide(Math.round(times(num, base)), base);
}
let _boundaryCheckingState = true;
/**
* 是否進行邊界檢查,默認開啟
* @param flag 標記開關,true 為開啟,false 為關閉,默認為 true
*/
// 這裡可以設置邊界檢查(默認是true)
function enableBoundaryChecking(flag = true) {
_boundaryCheckingState = flag;
}
// 輸出上面的方法
export { strip, plus, minus, times, divide, round, digitLength, float2Fixed, enableBoundaryChecking };
export default {
strip,
plus,
minus,
times,
divide,
round,
digitLength,
float2Fixed,
enableBoundaryChecking,
};
前端自動化測試框架Jest 基礎入門-
一、引言
前端這幾年發展的非常迅速,我們的系統的功能正在變的越來越複雜,這對我們的前端工程化能力提出了更高的要求,聽到工程化,大家的第一反應肯定是高質量的代碼設計和高質量的代碼實現。
但實際上,前端 自動化測試 也是前端工程化裡面非常重要的一個環節。
二、 Jest 基礎入門
一個普通前端聽到自動化測試,第一反應可能是:我工作這麼多年也沒寫過測試,這個東西有用嗎?
答:非常有用
如果你打開GitHub,去看一下流行的開源庫或者框架的源碼,你會發現,在這些源碼裡面,全部都包含了大量的自動化測試的代碼。比如antd、lodash、再比如vue、react、echarts、redux等等……
開源的工具需要穩定性,而引入前端自動化測試為開源項目提供穩定性,是再好不過的選擇了。
三、學習前提
閱讀這篇 文章 需要以下知識儲備:
·js、es6 基礎語法
·node、npm 相關知識
·git 的相關操作
·react或者vue,至少了解一個
·狀態管理工具,至少了解一個
四、背景及原理
首先在任意目錄下創建一個math.js文件,假設這個文件是一個數學庫,裡面定義兩個函數,分別是加法和減法:
// math.js
function add(a, b) {
return a + b;
}
function minus(a, b) {
return a – b;
}
這時候我們可以在業務代碼里去使用這個數學庫。
但是,假如,上面的minus函數我們不小心寫錯了,把減法寫成了乘法,如果直接在業務代碼中使用這個方法,就會帶來無法預期的bug。
所以這時候,我們就需要對math.js這個公共庫進行自動化測試,確保沒問題之後,再讓業務組件去調用,這樣就會保證不會出特別多的bug了。
我們可以這樣做:
在該目錄下創建一個math.test.js文件,然後寫一點測試代碼:
const result = add(3, 7);
const expect = 10;
if (result !== expect) {
throw new Error(`3 + 7 應該等於${expect},結果卻是${result}`);
}
const result = minus(3, 3);
const expect = 0;
if (result !== expect) {
throw new Error(`3 – 3 應該等於${expect},結果卻是${result}`);
}
這時候我們運行這段代碼,會發現沒有拋出任何異常,說明這兩個 測試用例 都通過了。
這就是自動化測試最原始的雛形。
然後我們思考一個問題,如何將這堆代碼進行簡化,做成一個公用的函數,比如這樣:
// 測試 3 + 3 是否等於 6
expect(add(3, 3)).toBe(6);
// 測試 3 – 3 是否等於 0
expect(minus(3, 3)).toBe(0);
expect 方法實現:
function expect(result) {
return {
toBe(actual) {
if (result !== actual) {
throw new Error(“預期值和實際值不相等”);
}
},
};
}
這時候我們運行這段代碼,會發現沒有拋出任何異常,說明這兩個測試用例都通過了。
雖然實現了 expect 函數,但是報錯的內容始終是一樣的,我們不知道是具體哪個方法出現了問題,這時候我們就會想到,我們需要將這個 expect 方法進一步做改良,我們如果能在 expect 方法外部再包裝一層,就可以多傳遞一些額外的內容,比如創造這樣的寫法:
test(“測試加法 3 + 3”, () = {
expect(add(3, 3)).toBe(6);
});
test(“測試減法 3 – 3”, () = {
expect(minus(3, 3)).toBe(0);
});
這樣封裝之後,我們既能進行測試,又能得到測試的描述。
test 方法實現:
function test(desc, fn) {
try {
fn();
console.log(`${desc} 通過測試`);
} catch {
console.log(`${desc} 沒有通過測試`);
}
}
所以前端自動化測試到底是什麼?
答:實際上就是寫了一段其它的用來測試的js代碼,通過測試代碼去運行業務代碼,判斷實際結果是否滿足預期結果,如果滿足,就是沒有問題,如果不滿足,就是有問題。
上面實現的 expect 方法 和 test 方法 實際上和主流的前端自動化測試框架 jest 裡面的語法是完全一致的。所以上面的示例代碼可以理解為 jest 的底層實現原理。
math是nodejs模塊嗎
是的
JavaScript起初並沒有內置的模塊系統,CommonJS社區為了使JavaScript可以提供一個類似Python、Ruby等的標準庫,自己實現了一套API填補了JavaScript沒有內置模塊的空白。
CommonJS規範本身涵蓋了模塊、二進位、Buffer、文件系統、包管理等內容,而NodeJS正是借鑒了CommonJS規範的模塊系統,自身實現了一套非常易用的模塊系統。CommonJS對模塊的定義可分為三部分:模塊引用(require)、模塊定義(exports、module)、模塊標識。
模塊引用:require函數用於引入外部模塊到當前上下文中
模塊定義:exports導出當前模塊的變數或方法,是唯一導出的出口。在模塊中,還有一個module對象,它代表模塊自身,且exports是module對象的屬性。
模塊標識:就是傳遞給require方法的參數。
在NodeJS中,每一個文件就是一個模塊,其內部定義的變數是屬於這個模塊的,不會對外暴露,也就是說不會污染全局變數。因此以上math.js模塊定義的PI常量不會作為全局變數存在,而是被包裹在NodeJS的模塊包裝器中,作為局部變數存在。math.js文件中通過exports對象導出該模塊下的circle方法,在main.js文件中通過require方法引入了circle方法。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/311582.html