JavaScript:覆盖构造函数中为整个类定义的属性

JavaScript:覆盖构造函数中为整个类定义的属性,javascript,Javascript,我试图覆盖类的函数: class MyClass { constructor() { // more code } myFunction = function() { console.log('not this') } } // can't change the code above MyClass.prototype.myFunction = function() { console.log('it should print this') } new

我试图覆盖类的函数:

class MyClass {
  constructor() {
    // more code
  }

  myFunction = function() {
    console.log('not this')
  }
}

// can't change the code above

MyClass.prototype.myFunction = function() {
  console.log('it should print this')
}

new MyClass().myFunction()
但巴贝尔将上述内容汇编为:

class MyClass {
  constructor() {
    // more code

    this.myFunction = function () {
      console.log('not this');
    };
  }
}

// can't change the code above

MyClass.prototype.myFunction = function () {
  console.log('it should print this');
};

new MyClass().myFunction();
因为函数在原始代码中定义为属性,所以Babel将该定义放在构造函数中。 如果我理解正确,原型只包含函数,而不是所有属性。 因为构造函数在对象从原型派生之后运行,所以我不能使用原型覆盖该函数

我的第二次尝试是覆盖构造函数:

class MyClass {
  constructor() {
    // more code
  }

  myFunction = function () {
    console.log('not this')
  }
}

// can't change the code above

let oldConstructor = MyClass.prototype.constructor
MyClass.prototype.constructor = function() {
  // call old constructor first, it will set myFunction
  oldConstructor()

  // now overwrite myFunction
  this.myFunction = function () {
    console.log('it should print this')
  }
}

new MyClass().myFunction()
好吧,让我们试试。。。 使用Babel编译,保存到test.js并运行:

~> node test.js
not this

我试图使这个问题尽可能笼统。关于为什么我不能在我的特定情况下更改类的更多背景信息:该类实际上来自我正在使用的库,我使用的其他包也依赖于该库。MeteorJS要求包指定其依赖项的确切版本和来源,这就是为什么我不能使用fork:我必须为依赖于此库的每个包提供fork

事实上,你正在改变你的课程,但它“不起作用”,因为。首先是对象内部的属性,然后是原型链

在第一个示例中,如果“删除”本地属性,则更改生效。例如:

    class MyClass {
  constructor() {
    // more code

    this.myFunction = function () {
      console.log('not this');
    };
  }
}

// can't change the code above

MyClass.prototype.myFunction = function () {
  console.log('it should print this');
};

const obj = new MyClass();
delete obj.myFunction;
obj.myFunction();

这是不可能做到的。无论何时实例化
MyClass
,都会重新定义内部的
myFunction
。但不是原型链中定义的
myFunction
。因此,解释器将首先在实例中查找方法,然后在原型链中查找。在原型链中定义可以用JavaScript覆盖的
方法

例如:

var a = new MyClass();
var b = new MyClass();

a.myFunction() === b.myFunction(); //false

a.__proto__.myFunction() === b.__proto__.myFunction() //true

由于原始问题没有解决方案,我最终使用了以下方法:

class MyClass {
  myFunction = function() {
    console.log('not this')
  }
}

class MyNewClass extends MyClass {
  myFunction = function() {
    console.log('should print this')
  }
}

new MyNewClass().myFunction()

显然,我现在必须一直使用MyNewClass,这是我并不想要的,最初的问题要求提供覆盖现有类函数的解决方案,但在我的情况下,这是可行的。

您可以通过在原型上放置getter/setter来截取赋值:

function myFunction() {
  console.log('it should print this');
}
Object.defineProperty(MyClass.prototype, "myFunction", {
  set(val) { /* ignore */ },
  get() { return myFunction; }
});

或者,对于ES6类,您也可以这样做。

正如我所说,我不能更改原始类,但我可以用继承重写构造函数,这不是我想要的,但它也可以工作。这个答案对找到解决方案没有太大帮助,但这是理解问题和结构最有帮助的答案。既然我不能把自己的答案标记为解决方案,我就把这个标记为解决方案,因为它帮助我理解了这个问题。