Image
是HTMLImageElement
的封装类,或者说HTMLImageElement
是Image
的基类。在前端开发中,创建一个图像有时会使用如下代码。
let img = new Image();
...
img.src = url;
return img;
如果重写src的set操作,可使用JavaScript
提供的defineProperty
方法,如下。
img._src = '';
Object.defineProperty(nativeImage, 'src', {
get: function() {
return this._src;
},
set: function(value) {
this._src = 'user://' + value;
}
});
这样每一次img.src=url
都会增加一个前缀'user://',但实际运用中,上述写法将会导致Image
无法加载,因为src的set操作不仅仅是赋值这么简单。所以,我们重写之后,还需要调用src的原有set操作,这样才不会改变原有逻辑。
要达到这个目的,可使用JavaScript
提供的getOwnPropertyDescriptor
方法,通过它先获取到原有对象中该元素的所有定义描述,包括函数调用,然后在重新定义中再调用原有方法。示例代码如下:
getOldProperty(obj, key) {
let target = obj;
while (true) {
if (!target) return obj;
if (target.hasOwnProperty(key)) break;
// 原型链回溯
target = (typeof target == 'function' ? target.prototype : target['__proto__']);
}
return Object.getOwnPropertyDescriptor(target, key);
}
let oldAttr = this.getOldProperty(img, 'src'); // 先获取src原有描述
if (oldAttr) {
// 再重新定义
img._src = '';
Object.defineProperty(img, 'src', {
enumerable: oldAttr.enumerable,
get: function() {
return this._src;
},
set: function(value) {
this._src = 'user://' + value;
oldAttr.set.call(this, this._src); // 调用原来的set
}
});
}
如上所示,修改了Image
或HTMLImageElement
的src
属性实现,且不会改变原有执行逻辑。