实现的方法有很多,以下介绍几种。
方法一
空数组 join
function repeat(target, n) {
return new Array(n + 1).join(target);
}
方法二
改良方法1,省去创建数组这一步,提高性能。之所以创建一个带 length 属性的对象,是因为要调用数组的原型方法,需要指定 call 第一个参数为类数组对象。
function repeat(target, n) {
return Array.prototype.join.call(
{
length: n + 1,
},
target,
);
}
方法三
改良方法 2,利用闭包缓存 join,避免重复创建对象、寻找方法。
var repeat = (function () {
var join = Array.prototype.join,
obj = {};
return function (target, n) {
obj.length = n + 1;
return join.call(obj, target);
};
})();
方法四
使用二分法,减少操作次数
function repeat(target, n) {
var s = target,
total = [];
while (n > 0) {
if (n % 2 === 1) {
total[total.length] = s;
}
if (n === 1) {
break;
}
s += s;
n = n >> 1; // Math.floor(n / 2);
}
return total.join("");
}
方法五
方法 4 的变种,免去创建数组与使用 join。缺点是循环中创建的字符串比要求的长。
function repeat(target, n) {
var s = target,
c = s.length * n;
do {
s += s;
} while ((n = n >> 1));
s = s.substring(0, c);
return s;
}
方法六
方法 4 的改良。
function repeat(target, n) {
var s = target,
total = "";
while (n > 0) {
if (n % 2 === 1) {
total += s;
}
if (n === 1) {
break;
}
s += s;
n = n >> 1;
}
return total;
}
方法七
与 6 相近,不过递归在浏览器中有优化。
function repeat(target, n) {
if (n === 1) {
return target;
}
var s = repeat(target, Math.floor(n / 2));
s += s;
if (n % 2) {
s += target;
}
return s;
}
方法八
一则反例,很慢,但是可行。
function repeat(target, n) {
return n <= 0 ? "" : target.concat(repeat(target, --n));
}
最后给出 MDN 中的String.prototype.repeat
的 polyfill 方法,大家也可以进行参考:
if (!String.prototype.repeat) {
String.prototype.repeat = function (count) {
"use strict";
if (this == null)
throw new TypeError("can't convert " + this + " to object");
var str = "" + this;
// To convert string to integer.
count = +count;
// Check NaN
if (count != count) count = 0;
if (count < 0) throw new RangeError("repeat count must be non-negative");
if (count == Infinity)
throw new RangeError("repeat count must be less than infinity");
count = Math.floor(count);
if (str.length == 0 || count == 0) return "";
// Ensuring count is a 31-bit integer allows us to heavily optimize the
// main part. But anyway, most current (August 2014) browsers can't handle
// strings 1 << 28 chars or longer, so:
if (str.length * count >= 1 << 28)
throw new RangeError(
"repeat count must not overflow maximum string size",
);
var maxCount = str.length * count;
count = Math.floor(Math.log(count) / Math.log(2));
while (count) {
str += str;
count--;
}
str += str.substring(0, maxCount - str.length);
return str;
};
}