为什么在javascript中过滤扩展数组的类的对象调用它的构造函数?

Sou*_*ver 3 javascript arrays constructor derived-class es6-class

我有这个示例代码:

class TestClass extends Array {
	constructor() {
		console.log( 'constructor' );
		
		let ar = [];
		ar.push( { id: 1, name: 'a' } );
		ar.push( { id: 2, name: 'b' } );
		ar.push( { id: 3, name: 'c' } );
		ar.push( { id: 4, name: 'd' } );
		
		// finalizing object
		super( ...ar );
	}
	
	Foo() {
		console.log( 'foo' );
		return this.filter( item => item.id > 2 );
	}
}

let t = new TestClass();
console.log( t.Foo() );
Run Code Online (Sandbox Code Playgroud)

这是我已经写的更简单的版本。我的应用程序运行到现在,但在我需要过滤扩展数组中的数据时停止了。我发现,问题是在我的类的对象上调用过滤器函数在内部调用构造函数。上面的代码显示了这个例子。有什么办法可以绕过这个问题,因为此时我无法再次调用构造函数。另外,我发现(使用这个简单的TestClass)实际输出不是我所期望的 - 我得到一个包含 4 个项目的数组,id 为 3、4、3、4。谁能解释这里发生了什么?

Pet*_*ger 6

Symbol.species provides a way to return not another instance of the derived class but for .e.g. in this case an Array instance again.

class TestClass extends Array {
  constructor() {
    console.log( 'constructor' );

    let ar = [];
    ar.push( { id: 1, name: 'a' } );
    ar.push( { id: 2, name: 'b' } );
    ar.push( { id: 3, name: 'c' } );
    ar.push( { id: 4, name: 'd' } );

    // finalizing object
    super( ...ar );
  }
  static get [Symbol.species]() { return Array; }

  Foo() {
    console.log( 'foo' );
    return this.filter( item => item.id > 2 );
  }
}

let t = new TestClass();
let a = t.Foo();

console.log('a : ', a);
console.log('(a instanceof Array) ? ', (a instanceof Array));
console.log('(a instanceof TestClass) ? ', (a instanceof TestClass));
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper { max-height: 100%!important; top: 0; }
Run Code Online (Sandbox Code Playgroud)


geo*_*org 5

根据规范,

Array.filter

  1. 让 A 成为?ArraySpeciesCreate(O, 0)。

(这里O是原始数组和A结果)

ArraySpeciesCreate

  1. 让 C ? 获取(原始数组,“构造函数”)。

通俗地说,就是X.filter创建一个新对象并将X的构造函数应用于它。这就是为什么你的构造函数被再次调用的原因。

一般来说,这种设计需要固定。你的TestClassextends Array,现在,如果你在整个应用程序中替换Arraywith TestClass,它的行为会一样吗?显然不是,这意味着您TestClass 违反了基本的 OOP 原则,即所谓的 LSP,应该重新设计(例如,通过聚合数组而不是扩展数组)。