admin管理员组文章数量:1334887
I have this example code:
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() );
I have this example code:
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() );
It is simpler version of what I've already written. My app worked up till now, but stopped the moment I needed to filter data in my extended array.
I've found out, that the problem is that calling a filter function on an object of my class internally calls constructor. The above code shows that example.
Is there any way to bypass this issue, because I can't call constructor again at this point. Also, I've found out (using this simple TestClass
) that actual output is not what I would expect - I get an array of 4 items with id's 3, 4, 3, 4. Can anyone explain what's happening here?
-
7
I'd imagine it's calling the constructor again because the
.filter()
method creates a new array. – Tyler Roper Commented Dec 3, 2018 at 15:42 -
I would advice to use
let ar
as your array and not extend the base Array. And foo() can the returnthis.ar.filter()
. – Shilly Commented Dec 3, 2018 at 15:46 - Yeah, just before I saw your answer it finally came to me. Instead of creating an Array, it creates another instance of my class. – Soul Reaver Commented Dec 3, 2018 at 15:46
- @Shilly I was going to do that in my first version, but I wanted to try to play with it a bit more (as I don't use JS too much, wanted to learn a bit) and give objects of this class an "indexer" ( object[i] ), but failed miserably. So I went with extending Array instead of using it internally. – Soul Reaver Commented Dec 3, 2018 at 15:49
-
Symbol.species
provides a way to return not another instance of the derived class but for .e.g. in this case anArray
instance again. – Peter Seliger Commented Dec 3, 2018 at 15:49
2 Answers
Reset to default 7Symbol.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));
.as-console-wrapper { max-height: 100%!important; top: 0; }
According to the spec,
Array.filter says
- Let A be ? ArraySpeciesCreate(O, 0).
(here, O
is the original array and A
the result)
and ArraySpeciesCreate says
- Let C be ? Get(originalArray, "constructor").
In layman's terms, X.filter
creates a new object and applies X
's constructor to it. That's why your constructor is called again.
In general, this design needs to be fixed. Your TestClass
extends Array
, now, if you replace Array
with TestClass
in the whole application, would it behave the same? Obviously not, which means that your TestClass
violates a fundamental OOP principle, so called LSP, and should be redesigned (for example, by aggregating an array instead of extending it).
本文标签:
版权声明:本文标题:Why in javascript filtering an object of a class that extends an Array calls it's constructor? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742241687a2438875.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论