参考答案

实现的方法有很多,以下介绍几种。

方法一

空数组 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; } }