JavaScript 中 repeat 的多种实现方法

最近翻回了 『JavaScript 框架设计』这本司徒正美编著,在 2014 年发行的书,此书主要讲述了从零开始写一个前端框架所要掌握的内容,每次阅读都会有新的收获。其中内容会在兼容性及性能上做很多考量,本文便是书中的一个关于字符串方法 repeat 实现的例子。

  1. 空数组 join
function repeat(target, n) {
  return (new Array(n + 1)).join(target);
}
  1. 改良方法 1,省去创建数组这一步,提高性能。另,之所以创建一个带 length 属性的对象,是因为要调用数组的原型方法,需要指定 call 第一个参数为类数组对象。
function repeat(target, n) {
  return Array.prototype.join.call({
    length: n + 1
  }, target);
}
  1. 改良方法 2,利用闭包缓存 join,避免重复创建对象、寻找方法。
var repeat = (function () {
  var join = Array.prototype.join, obj = {};
  return function(target, n) {
    obj.length = n + 1;
    return join.call(obj, target);
  };
})();
  1. 使用二分法,减少操作次数
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('');
}
  1. 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;
}
  1. 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;
}
  1. 与 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;
}
  1. 一则反例,很慢,但是可行。
function repeat(target, n) {
  return (n <= 0) ? "" : target.concat(repeat(target, --n));
}