实现Array.of方法

手写实现ES6中的Array.of静态方法,用于创建具有可变数量参数的新数组实例

问题

Array.of() 是 ES6 引入的一个静态方法,用于创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。它解决了 Array 构造函数在处理单个数字参数时的歧义问题(new Array(3) 创建长度为3的空数组,而 Array.of(3) 创建包含元素3的数组)。

我们需要实现一个 Array.of 方法,使其能够:

  • 接收任意数量的参数
  • 将所有参数作为数组元素返回
  • 行为与原生 Array.of() 一致

解答

/**
 * 实现 Array.of 方法
 * @param  {...any} args - 任意数量的参数
 * @returns {Array} 包含所有参数的新数组
 */
Array.myOf = function(...args) {
  // 方法1: 直接返回参数数组(最简洁)
  return args;
};

// 方法2: 使用传统方式(兼容性更好)
Array.myOf2 = function() {
  // 将 arguments 转换为真正的数组
  return Array.prototype.slice.call(arguments);
};

// 方法3: 完全模拟原生实现(更严谨)
Array.myOf3 = function() {
  var len = arguments.length;
  var result = new Array(len);
  
  // 遍历所有参数,逐个添加到结果数组中
  for (var i = 0; i < len; i++) {
    result[i] = arguments[i];
  }
  
  return result;
};

// 方法4: 支持子类化(最完整的实现)
if (!Array.of) {
  Array.of = function() {
    // 获取构造函数(支持子类)
    var C = this;
    var len = arguments.length;
    
    // 如果 C 不是构造函数,使用 Array
    var result = typeof C === 'function' 
      ? new C(len) 
      : new Array(len);
    
    // 填充元素
    for (var i = 0; i < len; i++) {
      result[i] = arguments[i];
    }
    
    return result;
  };
}

使用示例

// 基本使用
console.log(Array.myOf(1, 2, 3));           // [1, 2, 3]
console.log(Array.myOf(7));                 // [7]
console.log(Array.myOf());                  // []

// 对比 Array 构造函数的区别
console.log(new Array(3));                  // [empty × 3] 长度为3的空数组
console.log(Array.myOf(3));                 // [3] 包含元素3的数组

// 不同类型的参数
console.log(Array.myOf('hello', true, null, undefined, {a: 1}));
// ['hello', true, null, undefined, {a: 1}]

// 与原生方法对比
console.log(Array.of(1, 2, 3));             // [1, 2, 3]
console.log(Array.myOf(1, 2, 3));           // [1, 2, 3]

// 创建包含单个数字的数组
console.log(Array.myOf(100));               // [100]
console.log([100]);                         // [100] 等价写法

// 空调用
console.log(Array.myOf());                  // []
console.log([]);                            // [] 等价写法

关键点

  • 剩余参数语法:使用 ...args 可以最简洁地收集所有参数为数组
  • arguments 对象:在不支持 ES6 的环境中,可以使用 arguments 对象获取所有参数
  • 数组转换Array.prototype.slice.call(arguments) 是将类数组对象转换为真正数组的经典方法
  • 与构造函数的区别Array.of(7) 创建 [7],而 new Array(7) 创建长度为7的空数组
  • 子类化支持:完整实现需要考虑 this 指向,支持数组子类的创建
  • Polyfill 检查:实际使用时应先检查 Array.of 是否存在,避免覆盖原生实现
  • 性能考虑:直接返回剩余参数数组是最高效的实现方式