There’s an ECMAScript proposal to standarize String.prototype.padStart
and String.prototype.padEnd
. String padding is something that we’ve always had come across or implement ourselves one way or another.
Care to take a look?
(No, that’s not the kind of pads I was referring to. Yes, that’s my cat. Yes, she’s on top of my fridge. No, I never question her authority. Fine, I’ll get back on topic.)
Rationale
Before getting into the implementation, it might be useful to read about the rationale behind this addition to the language, which was put together by the people who drafted the proposal.
Without a reasonable way to pad a string using native methods, working with JavaScript strings today is more painful than it should be. Without these functions, the language feels incomplete, and is a paper cut to what could be a very polished experience.
Due to common use, string padding functions exist in a majority of websites and frameworks. For example, nearly every app in FirefoxOS had implemented a left pad function, because they all needed some generic string padding operation.
It is highly probable that the majority of current string padding implementations are inefficient. Bringing this into the platform will improve performance of the web, and developer productivity as they no longer have to implement these common functions.
Let’s look into .padStart
first.
String.prototype.padStart(max, fillString)
In its simplest incarnation, .padStart
will add enough spaces to the start of a string so that it arrives at the requested length.
'abc'.padStart(6);
// <- ' abc'
When a string’s length is at – or over – the specified max
length, no padding characters will be inserted.
'abc'.padStart(3);
// <- 'abc'
'abc'.padStart(2);
// <- 'abc'
Naturally you can change the padding character to something that’s not an space.
'abc'.padStart(5, 'x');
// <- 'xxabc'
The padding doesn’t need to be a single character either. The padding string is repeated as long as needed but it will be sliced to meet the character length requirement.
'abc'.padStart(7, 'xo');
// <- 'xoxoabc'
'abc'.padStart(6, 'xo');
// <- 'xoxabc'
An interesting use case for padStart
might be for providing input masks. The example below shows how you could implement such an input mask for ten-digit strings.
'1'.padStart(10, '0');
// <- '0000000001'
'12'.padStart(10, '0');
// <- '0000000012'
'123456'.padStart(10, '0');
// <- '0000123456'
How about dates?
'12'.padStart(10, 'YYYY-MM-DD');
// <- 'YYYY-MM-12'
'09-12'.padStart(10, 'YYYY-MM-DD');
// <- 'YYYY-09-12'
Here’s an adaptation of the reference polyfill stripped off sanity checks and all the usual spec-babble that makes these code snippets harder to read. If you want to use the method in an application today, I suggest you install the string.prototype.padstart
module, instead of copying and pasting the polyfill.
if (!String.prototype.padStart) {
String.prototype.padStart = function (max, fillString) {
return padStart(this, max, fillString);
};
}
function padStart (text, max, mask) {
const cur = text.length;
if (max <= cur) {
return text;
}
const masked = max - cur;
let filler = String(mask) || ' ';
while (filler.length < masked) {
filler += filler;
}
const fillerSlice = filler.slice(0, masked);
return fillerSlice + text;
}
Time to move onto .padEnd
.
String.prototype.padEnd(max, fillString)
This method is equivalent to .padStart
except for the fact that padding is appended to the string rather than prepended to it.
'123'.padEnd(6);
// <- '123 '
You can specify the padding character with .padEnd
as well.
'123'.padEnd(6, 'x');
// <- '123xxx'
Note that masking preserves the original padding, which may lead to confusion. For example, you may expect the following to produce '123456'
.
'123'.padEnd(6, '123456');
// <- '123123'
Similarly, you may want the following to produce '2016-MM-DD'
.
'2016'.padEnd(10, 'YYYY-MM-DD');
// <- '2016YYYY-M'
One work-around to get the desired result in these cases could be to just .slice
the mask against the length of the original string.
const year = '2016';
year.padEnd(10, 'YYYY-MM-DD'.slice(year.length));
// <- '2016-MM-DD'
Here’s an adaptation of the reference polyfill stripped off sanity checks and all the usual spec-babble that makes these code snippets harder to read. If you want to use the method in an application today, I suggest you install the string.prototype.padend
module, instead of copying and pasting the polyfill.
if (!String.prototype.padEnd) {
String.prototype.padEnd = function (max, fillString) {
return padEnd(this, max, fillString);
};
}
function padEnd (text, max, mask) {
const cur = text.length;
if (max <= cur) {
return text;
}
const masked = max - cur;
let filler = String(mask) || ' ';
while (filler.length < masked) {
filler += filler;
}
const fillerSlice = filler.slice(0, masked);
return text + fillerSlice;
}
As you can see above, the only difference between the polyfill for
.padStart
and the one for.padEnd
is what side oftext
thefillerSlice
portion of padded fill mask gets concatenated.
If you like this kind of article let me know and I’ll see what I can do to write more like it!
Comments