あなたが作成したメソッドが次のパラメータのテストに合格できる場合は、この記事をスキップしてください。
f(null); // invalid value
f(undefined); // invalid value
f(); // invalid value
f([12.888]); // invalid value
f('abc') // invalid value
f(NaN) // invalid value
f(0.1+0.2); // 0.30
f(0.3 - 0.2); // 0.10
f(1e3); // 1,000.00
f('1e3') // 1,000.00
f(123456) // 123,456.00
f(123456.456) // 123,456.46
f(12.899) // 12.90
f(12.999) // 13.00
f(10.055) // 10.06
f(10.005) // 10.01
f(10.105) // 10.11
f(10.155); // 10.16
f(10.105) // 10.11
f(0.0001) // 0.00
f(-10.105) // -10.11
f(.5) // 0.50
f(0/0) // invalid value
f(12/0) // invalid value
f(10 ** -4) // 0.00
それがうまくいかない場合は、以下を参照してください。
1: 方法の詳細な説明
アイデア:
- パラメータは文字列と数値形式 (負の数をサポート) のみをサポートしており、その他の形式はまだサポートされていません。
- パラメータは小数点以下第 2 位までに四捨五入されます。
- パラメータの整数の1000の位に区切り文字(,)が付加され、小数点以下2桁未満の末尾は0で埋められます。
1. パラメータは数値のみをサポートします
学生の中には、最初に .toString() をパラメータ化することを好む人もいるので、焦らないでください。
パラメータが null/未定義の場合、バックグラウンドによってパラメータが返されることがあります。もちろん、エラー報告も静かに待っています。
[12.888] を再度サイレントに渡し、配列が toString メソッドをカスタマイズし、結果は「12.888」を返しました。この時点では、プログラムは正常に実行できます。
したがって、パラメータは数値のみをサポートし、残りは直接「無効な値」を返すことに同意しましょう。この数値は数値型と文字列型に限定されますが、同時にisFinite (パラメーター) は true を返すことができます (そのため、あらゆる種類の付加機能を修正できます)。
isFinite は、最初にパラメーターを暗黙的に数値に変換します。NaN、Infinity、-Infinity をフィルターで除外します。
isFinite(Infinity) // false
isFinite(-Infinity) // false
isFinite(NaN) // false
isFinite(undefined) // false
isFinite(null) // true
isFinite(2) // true
isFinite(-2) // true
isFinite(.5) // true
isFinite(1e3) // true
isFinite([1]) // true
isFinite([1,2]) // false
isFinite({}) // false
isFinite(new Date()) // true
isFinite(/x/) // false
Number.isFinite() も使用できますが、パラメータを手動で数値に変換する必要があります。
最初はプランパラメータから変換した値がNaNでなければ良かったのですが、結果を検証するとIn,fin,ity.00というおかしな値が出ていました。それは自分自身で地雷を除去する方法でもあります。したがって、isFinite を思い切って使用してください。
したがって、この最初のステップは次のようになります。
function numberWithCommas(x, num = 2) {
// 以下两个方法都可以过滤NaN 和 Infinity/-Infinity,任选其一
let bool = isFinite(x); // 方法一
// let bool = Number.isFinite(Number(x)); // 方法二
if ((typeof x === 'string' || typeof x === 'number')
&& bool) {
return addCommas(round(x, num), num)
} else {
return "invalid value"
}
}
2. パラメータは小数点以下第 2 位までに四捨五入されます。
2桁まで四捨五入して、「できる!」と手を挙げた生徒もいました。to固定メソッド。もちろん、この答えを言った後は、そうはなりません。
さあ、さあ、栗を持って説明してください。
// 结果挺正常
(10).toFixed(2) // "10.00"
10.005.toFixed(2) // "10.01"
// 结果就挺不正常
(10.055).toFixed(2) // "10.05"
(10.135).toFixed(2) // "10.13"
したがって、toFixed() はあきらめてください。
- 方法1:手書きラウンド法、
- 方法 2: 巨人の肩の上に立つ (ここでは数値精度を使用する予定)
手書きの丸めメソッドでは、まず 100 を掛けて (カスタム回メソッド)、四捨五入し (Math.round())、次に 100 で割ります。
- パラメーターは 100 倍され、times メソッドがカスタマイズされます。数学的な計算(パラメータ * 100)を直接使用しない理由は、js では浮動小数点数の計算が不正確すぎるためです。
10.155*100 // 1015.4999999999999
10**-4 // 0.00009999999999999999
Math.pow(10,-4) // 0.00009999999999999999
0.1+0.2 // 0.30000000000000004
0.3-0.2 // 0.09999999999999998
- Math.round は正の数に非常に適していますが、パラメータが負の数の場合は問題が発生する可能性があります。
console.log(Math.round(1.1)) // 1
console.log(Math.round(1.5)) // 2
console.log(Math.round(1.6)) // 2
console.log(Math.round(-1.1)) // -1
console.log(Math.round(-1.5)) // -1
console.log(Math.round(-1.6)) // -2
したがって、最初にパラメータの絶対値を取得し、計算を完了してから、(負の数の場合) 符号を復元します。
したがって、2 番目のステップでは、以下のラウンド方法のいずれかを選択します。
最初の方法 (NP) - 推奨
// 安装 number-precision
npm install number-precision --save
// 使用
import NP from 'number-precision';
// 或
const NP = require('number-precision')
function round(num, decimal = 2) {
return NP.round(num, decimal)
}
2番目の方法(カスタマイズされたラウンド方法、NPのロープロファイルバージョン)
function round(num, decimal = 2) {
let base = Math.pow(10, decimal);
let result = Math.round(Math.abs(times(num, base))) / base;
if (num < 0 && result !== 0) {
result *= -1;
}
return result;
}
function times (num1, num2) {
const {val: val1, len: len1} = farmatVal(num1)
const {val: val2, len: len2} = farmatVal(num2)
return val1 * val2 / Math.pow(10, len1 + len2);
}
function farmatVal (num) {
// floatNoDot:浮点数去掉小数点
const floatNoDot = num => Number((num + '').replace('.', ''));
// decLength:浮点数小数的位数
const decLength = num => (((num + '').split('.'))[1] || '').length;
return {
val: floatNoDot(num),
len: decLength(num)
}
}
3. フォーマットして返します。整数に千の位の区切り文字を追加し、小数点以下 2 桁未満の末尾に 0 を追加します。
ついにメインディッシュが来ました。1000 分の 1 の区切りは、正規化する最も便利で簡潔な方法です。
しかし、私は自分自身に問いかけなければなりません、私はルールを守ることができるでしょうか?そうしますか?そうしますか?これは・・・あまり良くないです、分かりやすいですが、ちょっと難しいと読む範囲ではありません。
この 3 番目のステップでは、以下の addCommas メソッドのいずれかを選択できます。もちろん、書式設定方法を書くのが得意な方には、ここで私がペンを差し上げます。
最初の方法(通常)
function addCommas(x, num = 2) {
let [integer, decimals = ''] = (x + '').split('.')
// 添加千分位分隔符
integer = integer + ''
let pattern = /(-?\d+)(\d{3})/;
while (pattern.test(integer)) {
integer = integer.replace(pattern, '$1,$2')
}
// 尾部补零
decimals = (decimals + '0'.repeat(num)).slice(0, num)
return integer + '.' + decimals;
}
2 番目の方法 (通常)
function addCommas(x, num = 2) {
// 尾部补零
x = x + ''
x = x.replace(/^(-?\d+)$/, '$1.')
let reg = new RegExp(`(\\.\\d{${num}})\\d*$`)
x = (x + '0'.repeat(num)).replace(reg, '$1')
// 添加分隔符
x = x.replace('.', ',')
let pattern = /(\d)(\d{3},)/;
while (pattern.test(x)) {
x = x.replace(pattern, '$1,$2')
}
let regDec = new RegExp(`,(\\d{${num}})$`)
x = x.replace(regDec, '.$1')
return x;
}
3 番目の方法 (非正規): 整数配列の 1,000 桁ごとに区切り文字を追加し、それを文字列に変換します。
function addCommas(x, num = 2) {
// 符号位
let sign = x < 0 ? '-' : '';
let [
integer = '',
decimals = ''
] = (Math.abs(x).toString()).split('.');
// 整数位
let integerArr = [...integer];
for (let len = integerArr.length, i = len - 1; i > 0; i--) {
if ((len - 1 - i) % 3 === 2) {
integerArr.splice(i, 0, ',')
}
}
// 小数位补零
decimals = decimals.slice(0, num).padEnd(num, '0')
return sign + integerArr.join('') + '.' + decimals;
}
4番目の方法(非正規): 配列のreduceRightメソッドを使用してプロセスを蓄積します。
function addCommas(x, num = 2) {
let sign = x < 0 ? '-' : '';
let [
integer = '',
decimals = ''
] = (Math.abs(x).toString()).split('.');
// 整数位
let integerStr = ([...integer]).reduceRight((result, int, index, arr) => {
return int + ((arr.length - 1 - index) % 3 === 0 ? ',': '') + result
})
// 小数位补零
decimals = (decimals + '0'.repeat(num)).slice(0, num);
return sign + integerStr + '.' + decimals;
}
2: メソッドの検証
console.log(numberWithCommas(null)); // invalid value
console.log(numberWithCommas(undefined)); // invalid value
console.log(numberWithCommas()); // invalid value
console.log(numberWithCommas([12.888])); // invalid value
console.log(numberWithCommas('abc')); // invalid value
console.log(numberWithCommas(NaN)); // invalid value
console.log(numberWithCommas(0.1 + 0.2)); // 0.30
console.log(numberWithCommas(0.3 - 0.2)); // 0.10
console.log(numberWithCommas(1e3)); // 1,000.00
console.log(numberWithCommas('1e3')); // 1,000.00
console.log(numberWithCommas(123456)); // 123,456.00
console.log(numberWithCommas(123456.456)); // 123,456.46
console.log(numberWithCommas(12.899)); // 12.90
console.log(numberWithCommas(12.999)); // 13.00
console.log(numberWithCommas(10.055)); // 10.06
console.log(numberWithCommas(10.005)); // 10.01
console.log(numberWithCommas(10.105)); // 10.11
console.log(numberWithCommas(10.155)); // 10.16
console.log(numberWithCommas(-10.105)); // -10.11
console.log(numberWithCommas(.5)); // 0.50
console.log(numberWithCommas(0/0)); // invalid value
console.log(numberWithCommas(12/0)); // invalid value
console.log(numberWithCommas(10 ** -4)) // 0.00
基本的に要件は満たされていました。ただ問題は、JS言語の精度が2進数53桁までしかなく、絶対値が2の53乗以下の整数、つまり正確に表現できる整数でないと精度が保てないことです。2 の 53 乗は 16 桁の 10 進数値であるため、JavaScript は 15 桁の 10 進数値を正確に処理できます。整数の数字に小数点以下 2 桁を加えた数字が 15 桁を超える場合、結果は不正確になる可能性があります。
次に、金額を小数点以下 2 桁にフォーマットするのは日常的な操作です。ただし、違約金利息などの一部の値については、小数点以下 3 桁の書式設定要件がある場合があります。この記事で説明する書式設定方法は、小数点以下 3 桁の処理を満たしています。
終わり。