在JavaScript中扩展基类Array

myo*_*yol 8 javascript extend

我有一个扩展基数组类的自定义数组类.我有一个易于使用的自定义方法

export class ExampleArray extends Array {
    includesThing(thing) {
        ...

        return false
    }
}
Run Code Online (Sandbox Code Playgroud)

但是filter,map等的现有方法返回数组的实例.我想ExampleArray用这些方法返回一个实例.

我可以找到这些方法的接口,但不能找到它们的实现.如何调用父方法并返回我的自定义EampleArray?像下面这样的东西

export class ExampleArray extends Array {
    filter() {

    result = Array.filter()
    array = new ExampleArray()
    array.push(...result)

    return array
}
Run Code Online (Sandbox Code Playgroud)

或者这是扩展数组以制作自定义数组的正确方法吗?

Cer*_*nce 8

您需要阴影现有的.filter.map让,叫上一个实例时ExampleArray,你的功能将被调用,而不是 Array.prototype功能.在里面ExampleArray,您可以访问super.mapsuper.filter获取Array.prototype方法.例如:

class ExampleArray extends Array {
  constructor(...args) {
    super(...args);
  }
  hasMoreThanTwoItems() {
    // example custom method
    return this.length > 2;
  }
  isExampleArray() {
    return true;
  }
  
  // Shadow Array.prototype methods:
  filter(...args) {
    return new ExampleArray(
      // Spread the result of the native .filter into a new ExampleArray instance:
      ...super.filter.apply(this, args)
    );
  }
  map(...args) {
    return new ExampleArray(
      ...super.map.apply(this, args)
    );
  }
}

const exampleArray = new ExampleArray(3, 4, 5, 6, 7);

// true, filtering will result in 3 items
console.log(
  exampleArray
    .filter(e => e > 4)
    .hasMoreThanTwoItems()
);

// false, filtering will result in zero items
console.log(
  exampleArray
    .filter(e => e > 10)
    .hasMoreThanTwoItems()
);

// true, is an ExampleArray
console.log(
  exampleArray
    .map(e => e * 2)
    .isExampleArray()
);
Run Code Online (Sandbox Code Playgroud)

注意,也有其他的阵列方法,返回阵列,包括splice,slice和(实验)flatflatMap.如果你想那些返回一个自定义的类的实例,而不是默认的Array情况下,遵循相同的模式:暗影的Array.prototype函数名,并返回一个new ExampleArray填充的结果apply荷兰国际集团的Array.prototype方法:

<fnName>(...args) {
  return new ExampleArray(
    ...super.<fnName>.apply(this, args)
  );
}
Run Code Online (Sandbox Code Playgroud)


wor*_*gon 5

您不需要重写或重写 Array 的任何方法。只要确保你有一个合适的构造函数即可。

其工作原理在 ES6 规范中已添加强调):

9.4.2.3 ArraySpeciesCreate(originalArray, 长度)

...

令 C 为Get(originalArray, "constructor")。如果突然返回(C)。如果 IsConstructor(C) 为 true,则

...

这就是Array.filter用于创建新数组的方法 - 它获取原始对象的构造函数并使用它来构造过滤后的数组。

这是另一个答案中的代码,删除了重新定义的过滤器和映射方法,并且在没有它们的情况下它的工作方式相同。此代码(使用 Chrome 的控制台):

class ExampleArray extends Array {
  constructor(...args) {
    super(...args);
  }
  hasMoreThanTwoItems() {
    // example custom method
    return this.length > 2;
  }
  isExampleArray() {
    return true;
  }
}

const exampleArray = new ExampleArray(3, 4, 5, 6, 7);

// true, filtering will result in 3 items
console.log(
  exampleArray
    .filter(e => e > 4)
    .hasMoreThanTwoItems()
);

// false, filtering will result in zero items
console.log(
  exampleArray
    .filter(e => e > 10)
    .hasMoreThanTwoItems()
);

// true, is an ExampleArray
console.log(
  exampleArray
    .map(e => e * 2)
    .isExampleArray()
);
Run Code Online (Sandbox Code Playgroud)

产生这个输出:

true
false
true
Run Code Online (Sandbox Code Playgroud)

我必须补充一点,这通常不是扩展 javascript 类的好模型,但 Array 显然在设计上是可扩展的。