繁体   English   中英

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

[英]JavaScript: Overwrite property defined in constructor for whole class

我正在尝试覆盖一个类的功能:

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()

但是 Babel 将上面的内容编译为:

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 依赖于这个库的每个包。

实际上,您正在更改您的课程,但它“没有生效”,因为javascript 解释器如何在其对象中查找信息 首先,对象内部的属性,然后是原型链。

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

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();

https://jsbin.com/gixufadewu/edit?js,console

这是无法做到的。 每当您实例化MyClass时,内部的myFunction都会被重新定义。 但不是原型链中定义的myFunction 所以解释器会先在实例中查找方法,然后在原型链中查找。 在原型链中定义可以被 JavaScript 继承覆盖的methods

例如:

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,这是我并不真正想要的,并且最初的问题要求解决方案来覆盖现有 Class 的功能,但这在我的情况下有效。

您可以做的是通过在原型上放置一个 getter/setter 来拦截分配:

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

或者,您可以装饰构造函数,但对于 ES6 类,这意味着额外的预防措施

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM