《JavaScript 设计模式与开发实战》- 代理模式

178 阅读2分钟

代理模式

代理模式是对一个对象提供一个代用品或占位符,以便控制对它的访问。

代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象。

客户 -> 代理 -> 对象

代理分为保护代理和虚拟代理

保护代理会在代理拒绝或处理掉一些请求。用于控制不同权限的对象对目标对象的访问,但在 JavaScript 并不容易实现保护代理,因为我们没法判断谁访问了某个对象。

虚拟代理把一些开销很大的对象延迟到真正需要它的时候才去创建。

在传统面向对象语言中,需要保证代理对象和本体接口一致,以保证用户可以放心请求代理,以及在任何使用本体的地方都可以使用代理。

const myImage = (function() {
    const imgNode = document.createElement('img')
    document.body.appendChild(imgNode)

    return function(src) {
        imgNode.src = src
    }
})()

const proxyImage = (function() {
    const img = new Image

    img.onload = function() {
        myImage(this.src)
    }

    return function(src) {
        myImage('https://loading.jpg')
        img.src = src
    }
})()

proxyImage('xxx.jpg')

在这个例子中,本体和代理对象都为函数,必然能被执行,所以可以认为他们具有一致的接口。

在 JavaScript 中,说到代理,就不得不提到 Proxy 对象。Proxy 对象用于创建一个对象的代理,从而实现基本的拦截和自定义。(如属性查找、枚举、赋值、函数调用等)

我们可以用 proxy 把上面的例子重写一下。

function myImage() {
    const imgNode = document.createElement('img')
    const proxyImg = new Proxy(imgNode, {
        set(obj, key, value) {
            if(key === 'src') {
                const img = new Image
                img.src = value
                obj[key] = 'loading.jpg'
                console.log('start', obj);
                img.onload = function() {
                    obj[key] = value
                    console.log('onload', obj);
                }
            }
        }
    })
    return proxyImg
}

const proxyImg = myImage()
proxyImg.src = 'xxx.png'

可以看出,在 JavaScript 中,代理模式也是语言天然支持的,不需要像面向对象的语言一样定义代理类,因为 JavaScript 已经帮我们定义好了 Proxy。