native-class-ext
Version:
js原生对象增加常用方法
182 lines (170 loc) • 4.86 kB
JavaScript
(function(){
const defineProperty = require('./defineProperty.js')
/**
* 对Number类进行扩展
* @author gwl
* @since 2020年5月8日13:04:41
* js进行计算时有时会出现小数点导致计算错误,如
* 0.1+0.2=0.30000000000000004
* 0.3-0.2=0.09999999999999998
* 0.1*3=0.30000000000000004
* 2.4/0.8=2.9999999999999996
* 解决方法:转成整数计算
* */
function init(){
/**
* 加
* @param {Number} augend 被加数
* @return this+augend
* */
defineProperty(Number.prototype, '$add', add)
/**
* 减
* @param {Number} subtrahend 被减数
* @return this-subtrahend
* */
defineProperty(Number.prototype, '$subtract', subtract)
/**
* 乘
* @param {Number} multiplicand 乘数
* @return this*multiplicand
* */
defineProperty(Number.prototype, '$multiply', multiply)
/**
* 除
* @param {Number} divisor
* @param {Number} scale 保留小数位数
* @param {Number} roundingMode 舍入方式
* @return this/multiplicand
* */
defineProperty(Number.prototype, '$divide', divide)
/**
* 设置精度
* @param {Number} scale 小数位数,默认2
* @param {Number} roundingMode 舍入方式,默认Number.$ROUND_HALF_UP
* */
defineProperty(Number.prototype, '$setScale', setScale)
}
/** 进位, 1.01->1.1、-1.01->-1.1 */
defineProperty(Number, '$ROUND_UP', 0)
/** 舍弃, 1.01->1.0、-1.01->-1.0 */
defineProperty(Number, '$ROUND_DOWN', 1)
/** 常规四舍五入 */
defineProperty(Number, '$ROUND_HALF_UP', 4)
function add(augend){
const [num1, num2] = getEqScale(this, augend);
const res = parseInt(num1.numStr) + parseInt(num2.numStr);
return addPoint(res, num1.scale);
}
function subtract(subtrahend){
const [num1, num2] = getEqScale(this, subtrahend);
const res = parseInt(num1.numStr) - parseInt(num2.numStr);
return addPoint(res, num1.scale);
}
function multiply(multiplicand){
const num1 = getNumberInfo(this);
const num2 = getNumberInfo(multiplicand);
let res = parseInt(num1.numStr) * parseInt(num2.numStr);
return addPoint(res, num1.scale + num2.scale);
}
function divide(divisor, scale=2, roundingMode=Number.$ROUND_HALF_UP){
const [num1, num2] = getEqScale(this, divisor);
let res = parseInt(num1.numStr) / parseInt(num2.numStr);
return res.$setScale(scale, roundingMode);
}
function setScale(scale=2, roundingMode=Number.$ROUND_HALF_UP){
let no, res;
switch(roundingMode){
//常规四舍五入
case Number.$ROUND_HALF_UP: return parseFloat(this.toFixed(scale));
//舍弃
case Number.$ROUND_DOWN:
ni = getNumberInfo(this);
if(ni.scale == 0) return this;
res = ni.numSplit[0] + '.' + ni.numSplit[1].slice(0, scale);
return parseFloat(res);
//进位
case Number.$ROUND_UP:
ni = getNumberInfo(this);
if(ni.scale == 0) return this;
let scaleAfter = ni.numSplit[1].slice(scale);//, scale+1
if(scaleAfter) scaleAfter = parseInt(scaleAfter);
res = parseInt(ni.numSplit[0] + ni.numSplit[1].slice(0, scale));
if(scaleAfter>0) {
if(this>0) res++;
else if(this<0) res--;
}
return addPoint(res, scale);
}
}
/**
* 去小数点,并保证小数点移动位数相同
* */
function getEqScale(num1, num2){
num1 = getNumberInfo(num1);
num2 = getNumberInfo(num2);
const masScale = Math.max(num1.scale, num2.scale);
addZeroEnd(num1, masScale);
addZeroEnd(num2, masScale);
return [num1, num2];
}
/**
* 解析数字信息
* @return {Object}
* num {Number} 原数字
* numSplit {Array} 根据小数点拆成数组
* scale {Number} 小数点后位数
* numStr {String} 去小数点后字符串
* */
function getNumberInfo(num){
let numStr = num.toString();
const numSplit = numStr.split(".");
let scale = 0;
if(numSplit.length===2) {
scale = numSplit[1].length;
numStr = numSplit[0] + numSplit[1];
}
return {
num,
numSplit,
scale,
numStr
};
}
/**
* 在尾部添加0
* */
function addZeroEnd(numInfo, scale){
const offset = scale-numInfo.scale ;
if(offset > 0){
numInfo.scale = scale;
numInfo.numStr = numInfo.numStr + '0'.padEnd(offset, '0');
}
}
//添加小数点, addPoint(123, 2) = 1.23
function addPoint(num, scale=0){
if(scale === 0){
return num;
}
let isMinus = false
if(num < 0) {
isMinus = true
num = Math.abs(num)
}
let str = num.toString().padStart(scale, '0');
let res = str.slice(0, -scale);
if(!res){
res = '0';
}
let temp = str.slice(-scale);
if(temp){
res += '.' + temp;
}
res = parseFloat(res);
if(isMinus) {
res = 0-res
}
return res;
}
init();
})()