Javascript 重命名子类中的父类属性
在es2015中,如果我有基类来表示如下所示的Javascript 重命名子类中的父类属性,javascript,class,inheritance,ecmascript-6,Javascript,Class,Inheritance,Ecmascript 6,在es2015中,如果我有基类来表示如下所示的列表: class List { constructor(data){ this.data = data } sortBy(attribute){ return this.data.sort((a,b) => { return (a[attribute] < b[attribute]) ? 1 : -1; }) } get count() { return this.data.le
列表
:
class List {
constructor(data){
this.data = data
}
sortBy(attribute){
return this.data.sort((a,b) => {
return (a[attribute] < b[attribute]) ? 1 : -1;
})
}
get count() { return this.data.length }
}
class List {
constructor(data){ this.data = data; }
sortBy(attribute){
console.log("sortBy");
return this.data.sort( (a,b) => {
if (a[attribute] < b[attribute]) return -1;
if (a[attribute] > b[attribute]) return 1;
return 0;
});
}
get count() { return this.data.length; }
}
此时,除了名称之外,ToyList
与List
没有区别。但是如果您查看ToyList
的实例化,它既有数据
又有玩具
属性。就概念化ToyList
的点而言,data
没有多大意义,它们指的是同一个数组
如果我制作了一个ToyList
,我就同时拥有.data
和.toys
属性:
tl = new ToyList(['truck', 'plane', 'doll'])
Object { data: Array[3], toys: Array[3] }
那么我的tl
既有data
又有toys
属性。它们都是对同一数组的引用,但我希望子类只具有toys
引用
下面是另一个在基类上使用方法的示例:
class Todos extends List {
constructor(todos){
super(todos);
this.todos = todos;
}
get byPriority(){
return this.todos.sortBy('priority')
}
}
var thingsToDo = [
{task: 'wash the dog', priority: 10},
{task: 'do taxes', priority: 1},
{task: 'clean the garage', priority: 0}
]
var todos = new Todos(thingsToDo);
todos.byPriority
这将很好,因为这样我就可以参考.byPriority
,获得列表的排序版本,它非常特定于这种特殊类型的数据。但我看不出我怎么能做到,因为
但我得到的是:
TypeError: this.todos.sortBy is not a function
总之,我想要的是一种引用基类属性的方法,该属性的名称特定于子类的语义,而不会丢失基类的方法。引用我们在评论中的讨论,一个更好的实现(imo),可扩展并避免您所问的问题
var AP = Array.prototype; //just lazy
class List {
constructor(elements){
for(var i = 0, j = (elements && elements.length)|0; i<j; ++i)
this[i] = elements[i];
//use length instead of count, stay compatible with the Array-methods
//will make your life easier
this.length = i;
}
length: 0
sortBy(attr){
return this.sort(function(a,b){
return (a[attribute] < b[attribute]) ? 1 : -1
});
}
//some functions have to be wrapped, to produce a List of the right type
filter(fn){
return new (this.constructor)(AP.filter.call(this, fn));
}
clone(){ return new (this.constructor)(this) }
}
//some functions can simply be copied from Array
//no need to re-implement or even wrap them.
List.prototype.sort = AP.sort;
List.prototype.push = AP.push;
List.prototype.pop = AP.pop;
以及一个示例用法
class Toy {
constructor(name){
this.name = name;
}
}
var a = new ToyList([
new Toy("foo"),
new Toy("bar"),
"not a toy",
new Toy("baz")
])
console.log(a instanceof ToyList, a);
var b = a.filter(toy => toy.name.charAt(0) === "b");
console.log(b instanceof ToyList, b);
编辑:添加带有TODO的示例
class Todos extends List {
//don't even need a constructor, since I simply want to pass
//the array to the parent-constructor
//don't use getter for functionality, use methods!
byPriority(){
return this.sortBy('priority');
}
}
var thingsToDo = [
{task: 'wash the dog', priority: 10},
{task: 'do taxes', priority: 1},
{task: 'clean the garage', priority: 0}
]
var todos = new Todos(thingsToDo);
todos.byPriority()
在我看来,如果可能的话,更好的方法是将List类视为纯虚拟类,这意味着您永远不会创建该类的实例,而只是从该类扩展 纯虚拟类不应该有构造函数,方法应该假设存在某些属性。但是,实际上可以使用构造函数设置基类应用于“data”属性的名称
class List {
constructor(keyName) { this.keyName = keyName }
sortBy(attr) { return this[this.keyName].sort(...) }
}
class ToyList extends List {
constructor('toys') {
super(toys)
this.toys = toys;
}
}
ToyList
既有数据
又有玩具
属性。就概念化ToyList
的点而言,data
没有多大意义,它们指的是同一个数组
这是您的实际问题:您的ToyList
作为List
的子类没有意义
如果(出于任何原因)您的类应该类似于列表
,但没有数据
属性,那么它不再是子类。这将违反法律
现在你有什么选择
- 正如您已经考虑过的,您可以将其作为一个子类,其中更具体的
属性是.toys
的别名。这是非常好的,但是您不能避免在那里也有.data
属性data
- 您可能希望清除
数据
属性,并将元素直接存储在对象上。您的
类看起来像“数组,但带有有用的辅助函数”。如果这是你的意图,你应该考虑把它变成一个实际的子类:代码>数组< /COD>。托马斯的回答就是这个方向列表
- 你可能想优先于继承。您已经使用了这个概念-您的
实例在其列表
属性中包含数据
s。如果您有一个数组
或愿望列表
或其他专门处理惠斯或玩具的东西,并且有相应的方法,您可以简单地将一个玩具列表
实例存储在它们的列表
插槽中。.toys
实际上,您似乎期望您的
能够像这样工作,因为调用了TodoList
(其中this.todos.sortBy('priority')
将是一个this.todos
)。在子类上,只需列表
就可以完成这项工作this.sortBy('priority')
- 我真的不明白你的
是如何专门化ToyList
列表的。如果它除了名称之外没有什么特别之处,那么实际上可能不需要一个不同的类。如果JavaScript有泛型或类型变量,您可以使用
,但事实并非如此,因此您可以直接使用列表
列表
- 我想你有很多不同的问题
您的列表与
的定义有问题,您需要考虑3种情况,如下所示:
class List {
constructor(data){
this.data = data
}
sortBy(attribute){
return this.data.sort((a,b) => {
return (a[attribute] < b[attribute]) ? 1 : -1;
})
}
get count() { return this.data.length }
}
class List {
constructor(data){ this.data = data; }
sortBy(attribute){
console.log("sortBy");
return this.data.sort( (a,b) => {
if (a[attribute] < b[attribute]) return -1;
if (a[attribute] > b[attribute]) return 1;
return 0;
});
}
get count() { return this.data.length; }
}
让我们对TODO执行相同的操作:
class Todos extends List {
constructor(todos){ super(todos); }
get todos() { return data; }
get byPriority(){
return this.sortBy('priority');
}
}
byPriority
的定义有点奇怪,因为它具有边框效果(对元素进行排序)。我(个人)会把它作为一种标准方法来写
然后让我们做一些测试:
var thingsToDo = [
{task: 'wash the dog', priority: 10},
{task: 'do taxes', priority: 1},
{task: 'clean the garage', priority: 3}
];
var tl = new ToyList(['truck', 'plane', 'doll']);
for (var i=0; i<3; i++) {
console.log(tl.toys[i]); // access the *pseudo* toys attribute
}
var todos = new Todos(thingsToDo);
var r = todos.byPriority; // access the *pseudo* byPriority attribute (border effect: sorting internal data)
for (var i=0; i<3; i++) {
console.log(todos.data[i].priority);
}
var thingsToDo=[
{任务:'洗狗',优先级:10},
{任务:'纳税',优先级:1},
{任务:“清理车库”,优先级:3}
];
var tl=新玩具列表(['truck','plane','doll']);
对于(var i=0;iWell,如果您不想要List提供的功能,为什么要从List继承?似乎您的抽象需要重新评估!?我在基类中添加了两个以上的方法,以便更清楚地说明这一点。当然,在集合中还会有其他方法,您可以使用主干集合来执行这些操作n、 例如(排序、搜索、保存等)。我的问题是如何重写基类上的给定属性,以便派生类可以具有特定于域的方法和属性,而不是其他任何内容。不反对在派生类上添加附加功能。但只要您不将集合应用于数据
-属性,则列表将失败,您必须为派生类包装或重新实现它们;就像您使用get toyCount()
而不是使用get count()
所做的那样。整个方法毫无意义,只会增加复杂性。我将添加一个更好方法的示例。但我得到的是:TypeError:this.todos.sortBy
var thingsToDo = [
{task: 'wash the dog', priority: 10},
{task: 'do taxes', priority: 1},
{task: 'clean the garage', priority: 3}
];
var tl = new ToyList(['truck', 'plane', 'doll']);
for (var i=0; i<3; i++) {
console.log(tl.toys[i]); // access the *pseudo* toys attribute
}
var todos = new Todos(thingsToDo);
var r = todos.byPriority; // access the *pseudo* byPriority attribute (border effect: sorting internal data)
for (var i=0; i<3; i++) {
console.log(todos.data[i].priority);
}