使用 getter/setter 覆盖 javascript 属性,同时仍访问底层属性
Override javascript property with getter/setter while still accessing underlying property
为了构建 API polyfill,我想用 getter 和 setter 覆盖元素的属性(在本例中为宽度和高度),以捕获对值的更改并在将其传递给底层元素之前对其进行修改。理想情况下,此过程也是可逆的。类似于此代码片段的内容:
var realWidth = null;
function patch(targetObject) {
realWidth = targetObject.magicalPropertyAccessor("width");
Object.defineProperty(targetObject, 'width', {
get: function() {
return realWidth / 2;
},
set: function(value) {
realWidth = value * 2;
}
});
}
function unpatch(targetObject) {
if (realWidth)
targetObject.magicalPropertySetter('width', realWidth);
}
该示例的目的是,在修补元素时,它将静默地对其维度进行更改,同时报告原始的、未更改的值。如果这是一个函数,那将非常简单,但作为一个属性,不清楚如何缓存对原始访问器的引用。
多亏
了Bergi,我发现Object.getOwnPropertyDescriptor
正是我想要的。我以前试过,但错过了我必须去对象的__proto__
找到我正在寻找的属性的属性。(您的里程可能会因您要更换的属性而异。这是对我有用的代码:
function WidthPatch(canvas) {
var self = this;
var fakeWidth = canvas.width;
this.canvas = canvas;
// Cache the real property
this.realWidthProp = Object.getOwnPropertyDescriptor(canvas.__proto__, 'width');
// Replace the property with a custom one
Object.defineProperty(canvas, 'width', {
configurable: true,
enumerable: true,
get: function() {
return fakeWidth;
},
set: function(value) {
fakeWidth = value;
// This updates the real canvas property, silently doubling it.
self.realWidthProp.set.call(canvas, fakeWidth * 2);
}
});
}
WidthPatch.prototype.unpatch = function() {
// Replace the custom property with the original one.
Object.defineProperty(this.canvas, 'width', this.realWidthProp);
}
Reflect 为这个特定的用例提供了一些不错的(r) 语法。
下面的演示实现了一个"WidthPatch"类,该类覆盖了"width"属性,返回一个是实际值2倍的值,同时通过新的"actualWidth"属性提供对实际值的访问。 "UnPatch"方法删除修改的属性,恢复为原始行为。
class WidthPatch {
static #propertyName = 'width';
static #shadowPropertyName = 'actualWidth';
static Patch(instance) {
Reflect.defineProperty(instance, WidthPatch.#shadowPropertyName, {
get: _ => WidthPatch.#get(instance)
});
Reflect.defineProperty(instance, WidthPatch.#propertyName, {
configurable: true,
enumerable: true,
get: _ => 2 * WidthPatch.#get(instance),
set: value => Reflect.set(Reflect.getPrototypeOf(instance), WidthPatch.#propertyName, value, instance)
});
}
static UnPatch(instance) {
Reflect.deleteProperty(instance, WidthPatch.#propertyName);
}
static #get(instance) {
return Reflect.get(Reflect.getPrototypeOf(instance), WidthPatch.#propertyName, instance);
}
}
class Demo {
static {
const canvas = document.createElement('canvas');
console.log(`width (initial): ${canvas.width}`);
WidthPatch.Patch(canvas);
console.log(`width (after patching): ${canvas.width}, actualWidth: ${canvas.actualWidth}`);
canvas.width = 200;
console.log(`width (after setting to 200): ${canvas.width}, actualWidth: ${canvas.actualWidth}`);
WidthPatch.UnPatch(canvas);
console.log(`width (after unpatching): ${canvas.width}, actualWidth: ${canvas.actualWidth}`);
}
}
相关文章:
- JavaScript Pub/Sub属性访问问题
- AngularJS:如何用同一对象的另一个属性访问一个属性
- Ember JS属性访问器
- 对方法或属性访问的意外调用
- 对jQuery中IE8的方法或属性访问的意外调用
- 对方法或属性访问的意外调用.在JQUERY
- XDomainRequest onload上对方法或属性访问的意外调用
- Javascript属性访问速度:var.properties与var[“属性”]的区别
- 从函数属性访问对象属性;不适用于Firefox
- 重写内部 HTML 属性访问
- (仅在IE中)SCRIPT65535:对方法或属性访问的意外调用.主.js,第 152 行字符 28
- 使用表达式属性访问不同的模型模板选项
- jQuery mobile 1.1.0 滑块:JS-对象属性访问
- Ractive.js,通过命名属性访问父属性
- jQuery验证插件addMethod可以通过属性访问
- 如何使用动态属性访问对象
- 我无法通过 Firefox 中的“for”属性访问标签,但可以在 Chrome 中访问标签
- JavaScript 对象原型属性访问
- 使用虚拟属性访问猫鼬模型中的嵌套文档
- 是否可以在Javascript/Coffeescript中的属性访问期间自动调用函数调用