Javascript 如何更改类别';该类中运行时的原型(使用ES6类)

Javascript 如何更改类别';该类中运行时的原型(使用ES6类),javascript,ecmascript-6,Javascript,Ecmascript 6,我有下面的类“X”,我想动态地向它的原型添加一些东西,就像这样(这个工作起来): X类{ someUnrelatedFunction(){}; } //在运行时添加一些东西,在实际情况中,['a','b','c']并不像这里那样提前“知道”。 ['a','b','c'].forEach(elem=>{ X.prototype[elem]=()=>{ log('called with:'+elem); }; }) //测试: x=新的x(); x、 c()//工作,输出“调用:c”您可以使用继承

我有下面的类“X”,我想动态地向它的
原型添加一些东西,就像这样(这个工作起来):

X类{
someUnrelatedFunction(){};
}
//在运行时添加一些东西,在实际情况中,['a','b','c']并不像这里那样提前“知道”。
['a','b','c'].forEach(elem=>{
X.prototype[elem]=()=>{
log('called with:'+elem);
};
})
//测试:
x=新的x();

x、 c()//工作,输出“调用:c”您可以使用继承。创建新类
Y
,并从数组中添加它的方法。然后可以使用
Y
扩展原始类(或任何其他类):

class Y {}
const methods = ['a', 'b', 'c']
methods.forEach(elem => {
  Y.prototype[elem] = () => {
    console.log('called with : ' + elem)
  }
})

class X extends Y {
  someUnrelatedFunction() {}
}

const x1 = new X();
x1.a();
我不确定您的用例是什么,但您可以创建一个扩展原始类的helper函数。例如,这也可以起作用:

function extendWithMethods(methodNames, generalHandler) {
  class Y {}
  methodNames.forEach(elem => {
    Y.prototype[elem] = () => generalHandler(elem)
  })
  return Y
}

class X extends extendWithMethods(['a', 'b', 'c'], methodName => {
  console.log('called with : ' + methodName)
}) {
  someUnrelatedFunction() {}
}

const x1 = new X()
x1.a()

您可以使用继承。创建新类
Y
,并从数组中添加它的方法。然后可以使用
Y
扩展原始类(或任何其他类):

class Y {}
const methods = ['a', 'b', 'c']
methods.forEach(elem => {
  Y.prototype[elem] = () => {
    console.log('called with : ' + elem)
  }
})

class X extends Y {
  someUnrelatedFunction() {}
}

const x1 = new X();
x1.a();
我不确定您的用例是什么,但您可以创建一个扩展原始类的helper函数。例如,这也可以起作用:

function extendWithMethods(methodNames, generalHandler) {
  class Y {}
  methodNames.forEach(elem => {
    Y.prototype[elem] = () => generalHandler(elem)
  })
  return Y
}

class X extends extendWithMethods(['a', 'b', 'c'], methodName => {
  console.log('called with : ' + methodName)
}) {
  someUnrelatedFunction() {}
}

const x1 = new X()
x1.a()
我希望“原型”初始化属于类本身

这是不可能的。类主体只能包含方法定义,不能包含任意代码

如果方法的数量已知,并且只有它们的名称是动态的,那么您可以使用计算属性名称,但在您的示例中似乎不是这样

因为您正在寻找一种更具可读性的方法,所以只需将该类和静态值或动态创建的方法的所有赋值放在一个单独的模块中即可。(这可能是ES6模块、IIFE模块或用于视觉分离的简单块范围)

现在我正在
构造函数中执行此操作

不要。这是低效的、容易出错的,而且非常不可读

我希望“原型”初始化属于类本身

这是不可能的。类主体只能包含方法定义,不能包含任意代码

如果方法的数量已知,并且只有它们的名称是动态的,那么您可以使用计算属性名称,但在您的示例中似乎不是这样

因为您正在寻找一种更具可读性的方法,所以只需将该类和静态值或动态创建的方法的所有赋值放在一个单独的模块中即可。(这可能是ES6模块、IIFE模块或用于视觉分离的简单块范围)

现在我正在
构造函数中执行此操作


不要。这是低效的、容易出错的,而且非常不可读。

此类类原型修改从未从构造函数内部执行-主要是因为类构造函数负责管理当前类实例,而不是所有类实例。构造函数应该在
这个
类实例上声明新方法('log','info',等等),这比在类
原型
上声明方法效率低,并且对于进一步的类继承可能是可取的,也可能不是

这就是装饰的目的。它们为扩展或修改类构造函数和原型提供了方便的语法

装饰器可以修改现有的类
原型

function withLogger(Class) {
  ['log','info','error','warn','group','groupEnd'].forEach(func => {
    Class.prototype[func] = function() {
      return this.callConsoleMethod(func, ...arguments);
    };
  });

  return Class;
}
或者返回一个以非破坏性方式扩展现有类的新类,这允许在包装类中隐藏原始成员时使用
super

装饰器在ECMAScript Next/TypeScript中具有简洁的语法:

@withLogger
class YaLog {
  ...
}
由于decorator基本上是一个helper函数,因此可以在ES6中以一种不太表达的方式直接应用它:

const YaLog = withLogger(class YaLog {
  ...
});

此类类原型修改从未从构造函数内部执行-主要是因为类构造函数负责管理当前类实例,而不是所有类实例。构造函数应该在
这个
类实例上声明新方法('log','info',等等),这比在类
原型
上声明方法效率低,并且对于进一步的类继承可能是可取的,也可能不是

这就是装饰的目的。它们为扩展或修改类构造函数和原型提供了方便的语法

装饰器可以修改现有的类
原型

function withLogger(Class) {
  ['log','info','error','warn','group','groupEnd'].forEach(func => {
    Class.prototype[func] = function() {
      return this.callConsoleMethod(func, ...arguments);
    };
  });

  return Class;
}
或者返回一个以非破坏性方式扩展现有类的新类,这允许在包装类中隐藏原始成员时使用
super

装饰器在ECMAScript Next/TypeScript中具有简洁的语法:

@withLogger
class YaLog {
  ...
}
由于decorator基本上是一个helper函数,因此可以在ES6中以一种不太表达的方式直接应用它:

const YaLog = withLogger(class YaLog {
  ...
});

谢谢,但重点是要在这个课堂上做所有与任何给定课堂相关的事情。我重新表述了我的问题,并强调了“但是”:“但是在类声明本身中。”更清楚地说:)哇,我不知道我们可以做到这一点,即扩展。。。函数返回类:)谢谢!谢谢,但重点是要在这个课堂上做所有与任何给定课堂相关的事情。我重新表述了我的问题,并强调了“但是”:“但是在类声明本身中。”更清楚地说:)哇,我不知道我们可以做到这一点,即扩展。。。函数返回类:)谢谢!类语法本质上是以声明方式定义原型对象的便捷方法。由于您特别希望以编程方式执行,因此在类声明之外执行此操作对我来说非常合理。没有“正确”的方法来执行此操作。这种方法在设计上是错误的。如果你有一个具体的案例,你有可能有XY问题。请用相关细节更新问题,这样可以建议适当的替代方案。发布真实代码而不是ABC摘要也可能有助于理解问题。@logan