如何修改Image或HTMLImageElement的src属性实现

ImageHTMLImageElement的封装类,或者说HTMLImageElementImage的基类。在前端开发中,创建一个图像有时会使用如下代码。

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

如上所示,修改了ImageHTMLImageElementsrc属性实现,且不会改变原有执行逻辑。

标签:

发表回复

您的电子邮箱地址不会被公开。