gpt4 book ai didi

javascript - 在 JavaScript 中,特别是 NodeJS 上的 ES6,我可以在运行时直接操作类的 getter 和 setter 函数吗?

转载 作者:行者123 更新时间:2023-11-29 23:54:08 24 4
gpt4 key购买 nike

假设我有一个定义如下的类:

class MyClass {
constructor(a, b) {
this._a = a;
this._b = b;
}

get a() {
return this._a;
}

set a(val) {
this._a = val;
}

add() {
return this._a + this._b;
}
}

我希望能够在运行时直接访问和操作 getter 和 setter 函数,以便将它们包装在额外的调试代码中。使用“添加”功能,我可以这样做:

let oldAdd = MyClass.prototype.add;
MyClass.prototype.add = function() {
console.log('add called!');
let result = oldAdd.call(this);
console.log('add result: ' + result);
return result;
}

但是,我找不到以类似方式修改 getter 和 setter 函数的方法。

我试过了

let propDef = Reflect.getOwnPropertyDescriptor(MyClass.prototype, 'a');
propDef.get = function() {
// ...
}

但实际上并没有应用此更改。

有什么想法吗?

我也很想知道是否可以用同样的方式访问和修改构造函数。

最佳答案

是的,您可以通过重新配置属性来做到这一点。这是一个例子(见评论):

class MyClass {
constructor(a, b) {
this._a = a;
this._b = b;
}

get a() {
return this._a;
}

set a(val) {
this._a = val;
}

add() {
return this._a + this._b;
}
}

// Use it before redefining
const instance = new MyClass(1, 2);
console.log(instance.a); // 1
instance.a = 2;
console.log(instance.a); // 2

// Redefine the property
const desc = Reflect.getOwnPropertyDescriptor(MyClass.prototype, "a");
const {get: originalGet, set: originalSet} = desc;
desc.get = function() {
const value = originalGet.call(this);
console.log("Debugging 'get' here, a's value is " + value);
return value;
};
desc.set = function(newValue) {
console.log("Debugging 'set' here, a's new value is " + newValue);
originalSet.call(this, newValue);
};
Object.defineProperty(MyClass.prototype, "a", desc);

// Use it after redefining
console.log(instance.a); // 2, after seeing console statement
instance.a = 3; // Triggers another console statement
console.log(instance.a); // 3 (w/ console statement)

你所做的没有工作的部分原因是你从未在对象上设置新的描述符。您返回的描述符不提供对对象内定义的直接访问,它只是一个由 getOwnPropertyDescriptor 创建的新对象。要使更改生效,您需要设置新的描述符。


您在下面询问是否对 MyClass 本身执行相同的操作。正如您所指出的,除了替换函数外,我们还需要确保它的属性显示在它的替换项上。

一个简单易行的方法是让新函数继承旧函数:

const originalConstructor = MyClass;
MyClass = class MyClass extends originalConstructor {
constructor(...args) {
return new originalConstructor(...args);
}
};

一个鲜为人知的事实是,当 B 扩展 A 时,会发生两种事情:

  • B.prototype的原型(prototype)设置为A.prototype(这是众所周知的),
  • B的原型(prototype)设置为A(鲜为人知)

因此 A 上的任何静态信息都可以通过继承在 B 上使用。

所以:

class Base {
feature() {}
static staticFeature() {}
}
class MyClass extends Base {
subFeature() {}
static staticSubFeature() {}
}
const originalConstructor = MyClass;
MyClass = class MyClass extends originalConstructor {
constructor(...args) {
return new originalConstructor(...args);
}
};

console.log(typeof MyClass.staticFeature);
console.log(typeof MyClass.staticSubFeature);
const instance = new MyClass();
console.log(typeof instance.feature);
console.log(typeof instance.subFeature);

或者,如果您想要一个真正高保真的副本,您可以从 MyClass 的原型(prototype)派生,然后复制任何 MyClass 自己的属性;但它更复杂:

const originalConstructor = MyClass;
MyClass = class MyClass extends Object.getPrototypeOf(originalConstructor) {
constructor(...args) {
return new originalConstructor(...args);
}
};
Object.getOwnPropertyNames(originalConstructor)
.concat(Object.getOwnPropertySymbols(originalConstructor))
.forEach(name => {
MyClass[name] = originalConstructor[name];
});

例子:

class Base {
feature() {}
static staticFeature() {}
}
class MyClass extends Base {
subFeature() {}
static staticSubFeature() {}
}
const originalConstructor = MyClass;
MyClass = class MyClass extends Object.getPrototypeOf(originalConstructor) {
constructor(...args) {
return new originalConstructor(...args);
}
};
Object.getOwnPropertyNames(originalConstructor)
.concat(Object.getOwnPropertySymbols(originalConstructor))
.forEach(name => {
MyClass[name] = originalConstructor[name];
});

console.log(typeof MyClass.staticFeature);
console.log(typeof MyClass.staticSubFeature);
const instance = new MyClass();
console.log(typeof instance.feature);
console.log(typeof instance.subFeature);

关于javascript - 在 JavaScript 中,特别是 NodeJS 上的 ES6,我可以在运行时直接操作类的 getter 和 setter 函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42110019/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com