在 javascript 的 Array 子类中使用 .splice 方法?
Using .splice method in subclass of Array in javascript?
我正在尝试创建 javascript 数组的子 class。我想用数组类型的参数启动 subclass 并添加一个方法来从数组中删除一个元素 (subclass).
我的代码如下所示:
class CustomArray extends Array {
constructor(array) {
console.log('Initiating array:', array)
super(...array);
}
remove(element) {
let index = this.indexOf(element);
if (index > -1) {
return this.splice(index, 1);
}
return [];
}
}
var a = ['a', 'b', 'c', 'd', 'e'];
var list = new CustomArray(a)
console.log('list:', list);
console.log('remove:', list.remove('c'));
console.log('list:', list);
问题是,当我调用 .splice() 时,它会从数组中删除元素,还会删除 returns 数组中已删除的元素,实际上它 returns 是我的子 class CustomArray,应该以数组类型的参数启动,但是.splice()以整数类型的参数启动它。
这是我认为调用 .splice():
时发生的情况的示例
假设我们有 CustomArray
class 的实例 list
以参数 ['a','b','c','d','e']
启动,然后我们调用方法 list.remove('c')
。 (就像在代码片段中一样)。
CustomArray
class 的方法 remove
检查 c
的索引在数组 ['a','b','c','d','e']
中,即 2
然后调用 method this.splice(2,1)
这应该删除数组 ['a','b','c','d','e']
中索引 2 处的 1 个元素。方法 splice
从数组中删除元素 c
,但也 return 类似 new CustomArray(1)
的东西,因为从数组中删除了一个元素,因此它尝试创建长度为 1 的数组,但是失败,因为 class CustomArray
是期望数组。
我想阻止 splice
方法启动 CustomArray
class 的新实例,而不是 return 普通数组(Array 对象的实例)。
I want to prevent splice
method from initiating a new instance of CustomArray
class and instead return normal array (an instance of Array
object).
然后您需要创建一个不同名称的不同方法。 splice
的语义是 clearly and precisely defined;他们形成了 Array
类型的合同。让您的 CustomArray
违反该合同将意味着它不再是 Array
,而是 array-like,不应扩展 [=13] =].
既然你的方法被称为remove
,那很好;如果你想要remove
到returnArray
,而不是CustomArray
,你只需要自己实现逻辑:
remove(element) {
let index = this.indexOf(element);
if (index > -1) {
const newLength = this.length - 1;
while (index < newLength) {
this[index] = this[index + 1];
++index;
}
this.length = newLength;
return [element];
}
return [];
}
或者,当然,使 CustomArray
的构造函数在被各种 Array.prototype
方法调用时正确工作。 (除了用 console.log
记录您不期望的内容外,您在问题中遇到的那个工作得很好。)
可能有 splice
return 一个标准数组——所以不用它调用你的构造函数。它是通过更改自定义 class 的 @@species
property 来确定将使用哪个构造函数。但请注意,这不仅会影响 splice
,还会影响 所有 其他会创建新实例的方法,包括 map
、filter
、 slice
, ...
您可以通过覆盖相应的静态 getter:
来更改 @@species
属性
class CustomArray extends Array {
static get [Symbol.species]() { return Array; } // <-----------
constructor(array) {
console.log('Initiating array:', array)
super(...array);
}
remove(element) {
let index = this.indexOf(element);
if (index > -1) {
return this.splice(index, 1); // Now calls Array constructor, not CustomArray
}
return [];
}
}
var a = ['a', 'b', 'c', 'd', 'e'];
var list = new CustomArray(a)
console.log('list:', list);
console.log('remove:', list.remove('c'));
console.log('list:', list);
// Some examples of effects on other methods
console.log(list.map(x => x) instanceof CustomArray); // false
console.log(list.filter(x => 1) instanceof CustomArray); // false
console.log(list.slice() instanceof CustomArray); // false
console.log(list.concat() instanceof CustomArray); // false
// Other methods, that do not return a new instance, are not affected:
console.log(list.reverse() instanceof CustomArray); // true
console.log(list.sort() instanceof CustomArray); // true
我正在尝试创建 javascript 数组的子 class。我想用数组类型的参数启动 subclass 并添加一个方法来从数组中删除一个元素 (subclass).
我的代码如下所示:
class CustomArray extends Array {
constructor(array) {
console.log('Initiating array:', array)
super(...array);
}
remove(element) {
let index = this.indexOf(element);
if (index > -1) {
return this.splice(index, 1);
}
return [];
}
}
var a = ['a', 'b', 'c', 'd', 'e'];
var list = new CustomArray(a)
console.log('list:', list);
console.log('remove:', list.remove('c'));
console.log('list:', list);
问题是,当我调用 .splice() 时,它会从数组中删除元素,还会删除 returns 数组中已删除的元素,实际上它 returns 是我的子 class CustomArray,应该以数组类型的参数启动,但是.splice()以整数类型的参数启动它。
这是我认为调用 .splice():
时发生的情况的示例假设我们有 CustomArray
class 的实例 list
以参数 ['a','b','c','d','e']
启动,然后我们调用方法 list.remove('c')
。 (就像在代码片段中一样)。
CustomArray
class 的方法 remove
检查 c
的索引在数组 ['a','b','c','d','e']
中,即 2
然后调用 method this.splice(2,1)
这应该删除数组 ['a','b','c','d','e']
中索引 2 处的 1 个元素。方法 splice
从数组中删除元素 c
,但也 return 类似 new CustomArray(1)
的东西,因为从数组中删除了一个元素,因此它尝试创建长度为 1 的数组,但是失败,因为 class CustomArray
是期望数组。
我想阻止 splice
方法启动 CustomArray
class 的新实例,而不是 return 普通数组(Array 对象的实例)。
I want to prevent
splice
method from initiating a new instance ofCustomArray
class and instead return normal array (an instance ofArray
object).
然后您需要创建一个不同名称的不同方法。 splice
的语义是 clearly and precisely defined;他们形成了 Array
类型的合同。让您的 CustomArray
违反该合同将意味着它不再是 Array
,而是 array-like,不应扩展 [=13] =].
既然你的方法被称为remove
,那很好;如果你想要remove
到returnArray
,而不是CustomArray
,你只需要自己实现逻辑:
remove(element) {
let index = this.indexOf(element);
if (index > -1) {
const newLength = this.length - 1;
while (index < newLength) {
this[index] = this[index + 1];
++index;
}
this.length = newLength;
return [element];
}
return [];
}
或者,当然,使 CustomArray
的构造函数在被各种 Array.prototype
方法调用时正确工作。 (除了用 console.log
记录您不期望的内容外,您在问题中遇到的那个工作得很好。)
可能有 splice
return 一个标准数组——所以不用它调用你的构造函数。它是通过更改自定义 class 的 @@species
property 来确定将使用哪个构造函数。但请注意,这不仅会影响 splice
,还会影响 所有 其他会创建新实例的方法,包括 map
、filter
、 slice
, ...
您可以通过覆盖相应的静态 getter:
来更改@@species
属性
class CustomArray extends Array {
static get [Symbol.species]() { return Array; } // <-----------
constructor(array) {
console.log('Initiating array:', array)
super(...array);
}
remove(element) {
let index = this.indexOf(element);
if (index > -1) {
return this.splice(index, 1); // Now calls Array constructor, not CustomArray
}
return [];
}
}
var a = ['a', 'b', 'c', 'd', 'e'];
var list = new CustomArray(a)
console.log('list:', list);
console.log('remove:', list.remove('c'));
console.log('list:', list);
// Some examples of effects on other methods
console.log(list.map(x => x) instanceof CustomArray); // false
console.log(list.filter(x => 1) instanceof CustomArray); // false
console.log(list.slice() instanceof CustomArray); // false
console.log(list.concat() instanceof CustomArray); // false
// Other methods, that do not return a new instance, are not affected:
console.log(list.reverse() instanceof CustomArray); // true
console.log(list.sort() instanceof CustomArray); // true