Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 94dc8ee

Browse files
refact(formatNumber): optimisations
1 parent 91a8b9f commit 94dc8ee

File tree

1 file changed

+47
-40
lines changed

1 file changed

+47
-40
lines changed

src/ng/filter/filters.js

+47-40
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
'use strict';
22

3+
var MAX_DIGITS = 22;
4+
var DECIMAL_SEP = '.';
5+
var ZERO_CHAR = '0';
6+
37
/**
48
* @ngdoc filter
59
* @name currency
@@ -137,10 +141,16 @@ function numberFilter($locale) {
137141
};
138142
}
139143

140-
var MAX_DIGITS = 22;
141-
var DECIMAL_SEP = '.';
142-
var ZERO_CHAR = '0';
143-
144+
/**
145+
* parse a number (as a string) into three components that can be used
146+
* for formatting the number
147+
* @param {string} numStr The number to parse
148+
* @return {object} An object describing this number, containing the following keys:
149+
* - d : an array of digits containing leading zeros as necessary
150+
* - i : the number of the digits in `d` that are to the left of the decimal point
151+
* - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d`
152+
*
153+
*/
144154
function parse(numStr) {
145155
var exponent = 0, digits, integerLen;
146156
var e, i, j, zeros;
@@ -184,47 +194,48 @@ function parse(numStr) {
184194
integerLen = 1;
185195
}
186196

187-
return { digits: digits, exponent: exponent, integerLen: integerLen };
197+
return { d: digits, e: exponent, i: integerLen };
188198
}
189199

200+
/**
201+
* Round the parsed number to the specified number of decimal places
202+
* This function changed the parsedNumber in-place
203+
*/
190204
function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
191-
var digit = 0;
192-
var digits = parsedNumber.digits;
193-
var fractionLen = digits.length - parsedNumber.integerLen;
205+
var digits = parsedNumber.d;
206+
var fractionLen = digits.length - parsedNumber.i;
194207

195-
// determine fractionSize if it is not specified
196-
if (isUndefined(fractionSize)) {
197-
fractionSize = Math.min(Math.max(minFrac, fractionLen), maxFrac);
198-
}
208+
// determine fractionSize if it is not specified; `+fractionSize` converts it to a number
209+
fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;
199210

200-
// Cut off unwanted digits with rounding
201-
for (; fractionLen > fractionSize && digits.length; fractionLen--) {
202-
digit = digits.pop();
203-
// Round up if necessary
204-
if (digit >= 5) digits[digits.length - 1]++;
205-
}
211+
// The indec of the digit to where rounding is to occur
212+
var roundAt = fractionSize + parsedNumber.i;
213+
var digit = digits[roundAt];
206214

207-
if (!digits.length) {
215+
if (roundAt > 0 ) {
216+
digits.splice(roundAt);
217+
} else {
208218
// We rounded to zero so reset the parsedNumber
209-
parsedNumber.integerLen = 1;
210-
// If the last removed digit was >= 5 then we need to round up
211-
if (digit >= 5) digits.push(1);
212-
// Pad out with the necessary zeros
213-
while (digits.length <= fractionSize) digits.unshift(0);
219+
parsedNumber.i = 1;
220+
digits.length = roundAt = fractionSize+1;
221+
for(var i=0; i<roundAt; i++) digits[i] = 0;
214222
}
215223

224+
if (digit >= 5) digits[roundAt-1]++;
225+
216226
// Pad out with zeros to get the required fraction length
217-
for (; fractionLen < fractionSize; fractionLen++) digits.push(0);
227+
for (; fractionLen < fractionSize; fractionLen++) digits.push(0);
228+
218229

219-
// Do a final clear of any carrying, e.g. the last digit was rounded up to 10
230+
// Do any carrying, e.g. a digit was rounded up to 10
220231
var carry = digits.reduceRight(function(carry, d, i, digits) {
221232
d = d + carry;
222233
digits[i] = d % 10;
223234
return Math.floor(d / 10);
224235
}, 0);
225236
if (carry) {
226237
digits.unshift(carry);
227-
parsedNumber.integerLen++;
238+
parsedNumber.i++;
228239
}
229240
}
230241

@@ -248,16 +259,11 @@ function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
248259
*/
249260
function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
250261

251-
if (isObject(number)) return '';
252-
253-
var isNegative = number < 0;
254-
number = Math.abs(number);
255-
256-
var isInfinity = number === Infinity;
257-
if (!isInfinity && !isFinite(number)) return '';
262+
if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';
258263

264+
var isInfinity = !isFinite(number);
259265
var isZero = false;
260-
var numStr = number + '',
266+
var numStr = Math.abs(number) + '',
261267
formattedText = '',
262268
parsedNumber;
263269

@@ -268,8 +274,9 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
268274

269275
roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);
270276

271-
var digits = parsedNumber.digits;
272-
var integerLen = parsedNumber.integerLen;
277+
var digits = parsedNumber.d;
278+
var integerLen = parsedNumber.i;
279+
var exponent = parsedNumber.e;
273280
var decimals = [];
274281
isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true);
275282

@@ -305,11 +312,11 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
305312
formattedText += decimalSep + decimals.join('');
306313
}
307314

308-
if (parsedNumber.exponent) {
309-
formattedText += 'e+' + parsedNumber.exponent;
315+
if (exponent) {
316+
formattedText += 'e+' + exponent;
310317
}
311318
}
312-
if (isNegative && !isZero) {
319+
if (number < 0 && !isZero) {
313320
return pattern.negPre + formattedText + pattern.negSuf;
314321
} else {
315322
return pattern.posPre + formattedText + pattern.posSuf;

0 commit comments

Comments
 (0)