JavaScript 如何“决定”如何打印类名?

问题描述 投票:0回答:1

我正在尝试编写一个继承逻辑,在其中克隆输入类并从剩余的父类继承。为了做到这一点,我需要创建一个新类,精确地深度复制其中一个类。我正在努力实现类似的目标: class Original {static b=1; static test2(){}; test(){}} var CopyClass = DeepCopySomehow(Original) class NotWorking extends Original{} console.log(Object.getOwnPropertyNames(NotWorking)) // [ 'length', 'name', 'prototype'] console.log(Object.getOwnPropertyNames(Original)) // [ 'length', 'name', 'prototype', 'test2', 'b' ] console.log(Object.getOwnPropertyNames(NotWorking.prototype)) // ['constructor'] console.log(Object.getOwnPropertyNames(Class.prototype)) // ['constructor', 'test']

我有类似(简化)的东西:

function inherit(Class1, Class2) { class Base extends Class1 {...stuff...} Object.defineProperty(Base, 'name', {value: Class1.name}); copy_props(Base.prototype, Class1.prototype); copy_props(Base, Class1.prototype); copy_props(Base.prototype, Class2.prototype); copy_props(Base, Class2.prototype); }

但是,这仍然以某种方式保留了“Base”的信息。 

浏览器端
——这是一个可重现的示例: class SpecificParentName{constructor() {return new Proxy(this, {})}} const Base = class extends SpecificParentName{constructor(...args){super(...args)}} Base.toString = () => SpecificParentName.toString() Object.defineProperty(Base, 'name', {value: SpecificParentName.name}); console.log(Base) // class extends SpecificParentName{constructor(...args){super(...args)}} // reasonable output, although I would have wanted it to be just class SpecificParentName if possible console.log(new Base()) // Proxy(Base) {} // definitely not desired, because it doesn't point to SpecificParentName console.log(new Proxy(Base, {})) // Proxy(Function) {length: 0, name: 'SpecificParentName', prototype: SpecificParentName} // it's ok since points to SpecificParentName

Nodejs 端

-- 我之前在 Nodejs 端也遇到过类似的问题: class SpecificParentName{} console.log(SpecificParentName) // "[class SpecificParentName]" const Base = class extends SpecificParentName{} console.log(Base) // [class Base extends SpecificParentName] // I'd like this^ to be just "[class SpecificParentName]" // hacky fix on nodejs: const Base2 = class extends SpecificParentName{ static [require('util').inspect.custom]() {return `[class ${SpecificParentName.name}]`} console.log(Base2) // "[class SpecificParentName]" }

所以我的问题是,javascript 为什么以及如何知道我在打印时定义类时使用的变量名称,有没有办法自定义它?

javascript class dynamic constructor subclassing
1个回答
0
投票
问。 “JavaScript 如何“决定”如何打印类名?”

首先,每个函数(包括类构造函数)都有一个
自己的

name属性

其次,如何公开这个名称是函数类型特定的

toString

 实现的一部分。对于内置类型的实例,类名会通过初始 
Symbol.toStringTag
 实现另外公开。自定义类实现的实例不会显示后一种行为(它们的默认值始终返回 
'[object Object]'
)。
最后,两个实现都可以被覆盖;至于函数名称(包括类构造函数),任何分配给变量或属性的未命名/匿名函数或类表达式都会将此变量或属性的名称分配给其自己的 

name

属性。

因此,OP想要实现的一切都可以通过

动态子类化/子类型

模式来完成,实现为创建命名子类的单个工厂函数 该函数确实需要 3 个参数...

    稍后公开
  1. 类名

    对于创建并返回的子类一次,
    • 子类的
    • toString
    • 方法两次,
      第三个用于返回由 
    • Object.prototype.toString.call(subclassInstance)
    •  处理的每个实例的实现细节
      
  2. 要扩展的
  3. 超级或基类

  4. 可选的
  5. 初始化函数

    ,在一定程度上确实涵盖了构造函数的功能。

  6. 示例代码...

class SpecificParentName {} console.log({ SpecificParentName, 'SpecificParentName.name': SpecificParentName.name, }); /* * ... OP's request ... */ const Base = createNamedSubclass('SpecificParentName', SpecificParentName); console.log({ Base, 'Base.name': Base.name, }); const baseInstance = new Base; console.log( 'Object.prototype.toString.call(baseInstance) ...', Object.prototype.toString.call(baseInstance) );
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
function createNamedSubclass(
  className = 'UnnamedType' ,
  baseClass = Object,
  initializer = (...args) => args,
) {
  const subClass = ({
  
    // - ensures the class constructor's name.
    [className]: class extends baseClass {
    
      constructor(...args) {

        super(...args);

        initializer.apply(this, args);
      }
    },
  })[className];

  // - responsible for exposing the constructor's intended stringification.
  Reflect.defineProperty(subClass, 'toString', {
    value: () => `class ${ className }{}]`,
  });
  
  // - responsible for exposing an instance' class implementation detail.
  Reflect.defineProperty(subClass.prototype, Symbol.toStringTag, {
    get: () => className,
  });

  return subClass;
}
</script>

人们可以通过阅读例如《动态子类化/子类型化》等内容来更深入地研究动态子类化/子类型化问题。

“如何从给定类动态创建子类并增强/扩充子类构造函数的原型?”

© www.soinside.com 2019 - 2024. All rights reserved.