【问题标题】:Subclassing JavaScript arrays - constructor arguments not passing to array子类化 JavaScript 数组 - 构造函数参数不传递给数组
【发布时间】:2016-04-20 11:13:08
【问题描述】:

我想继承一个 javascript 数组并将构造函数参数传递给数组。我所拥有的是:

function SubArray(arguments) {
    Array.apply(this, arguments);
}

SubArray.prototype = Array.prototype;

测试不表明参数正在传递给数组

var x = new SubArray("One", "Two", "Three");
// Object[]
// x.length = 0

而当我使用数组执行此操作时,我得到了这个

var x = new Array("One", "Two", "Three");
// Object["One", "Two", "Three"]
// x.length = 3

我做错了什么?

【问题讨论】:

  • Array 是一个 DOM 宿主对象,遗憾的是你不能像这样扩展它 :( 如你所见,.length 不会按预期工作,.apply 不会按预期工作,您必须创建一个普通的 Array 实例并根据需要向其添加属性
  • 你需要 ES6 来继承 Array 对象。它被认为是一个奇特的对象(由于其特殊的.length 属性),在尝试在 ES5 或更早版本中进行子类化时会出现问题。

标签: javascript arrays inheritance prototype


【解决方案1】:

ES6

在 ES6 中,您可以使用 class 语法扩展 Array

class SubArray extends Array {
    constructor() {
        super(...arguments);
    }
    first() {
        return this[0];
    }
}

长度将按预期工作

var sa = new SubArray('foo', 'bar');
sa[2] = 'baz';
sa.length; // 3
sa.first(); // "foo"
sa instanceof SubArray; // true

ES5 之前

在 ES5 之前(包括 ES5),无法在不丢失功能的情况下以通常的构造函数原型方式干净地扩展 Array,而是必须向 Array 实例添加属性

function SubArray() {
    var arr = Array.apply(null, arguments);
    arr.first = function () {return this[0];};
    return arr;
}

使用它不再需要new,因为从函数返回Objectinstanceof 将无法确定SubArray

var sa = SubArray('foo', 'bar');
sa[2] = 'baz';
sa.length; // 3
sa.first(); // "foo"
sa instanceof SubArray; // false -- this gets broken

ES5(慢)

在行为比速度更重要的 ES5 环境中,您可以根据需要使用 Object.setPrototypeOf (see MDN warning) 强制原型链,这“有点小技巧”看起来像 p>

function SubArray() {
    var arr = Array.apply(null, arguments);
    Object.setPrototypeOf(arr, SubArray.prototype);
    return arr;
}
SubArray.prototype = Object.create(Array.prototype);
SubArray.prototype.first = function () {return this[0];};

同样,new 不再需要,但这次实例的行为与正常扩展时的预期行为完全相同。

var sa = SubArray('foo', 'bar');
sa[2] = 'baz';
sa.length; // 3
sa.first(); // "foo"
sa instanceof SubArray; // true

【讨论】:

  • 想必ES6还没有被完全采用,所以可能会出现兼容性问题?
  • @series0ne 是的,即使在像 Chrome 这样的浏览器中,您现在也必须在 "use strict"; 中才能工作。我也提供了 ES5 解决方案
  • 我有点晚了,但总结一下:function SubArray() { return Array.apply(this, arguments) }; SubArray.prototype = Array.prototype; new SubArray("One", "Two", "Three") 也很好用。
  • @Lapys 如果你这样做然后添加一些东西到SubArray.prototype 它也会被添加到Array.prototype (因为它是同一个对象),所以你已经用 Array.prototype >子数组代码
猜你喜欢
  • 1970-01-01
  • 2017-01-02
  • 2015-06-12
  • 2012-08-25
  • 2015-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多