Proxy代理

更新日期: 2020-02-29阅读: 3.8k标签: 代理

Proxy对象

在一个系统中,总要存储一些数据,对于这些数据,可能有一些是希望我们访问的,但是总有一些是中重要的,不希望我们访问的,希望保护起来,因此ES6新增了代理,在目标对象前架设个“拦截“层,外界对该对象的访问必须通过这层拦截,我们可以对外界的访问进行过滤和改写。

注意:Proxy修改了某些操作的默认行为,等同于在语言层做出修改,所以也属于”元编程“,即对语言进行编程。

语法: let proxy = new Proxy(target,handler)

target 表示被代理的对象

handler 表示操作被代理的对象

注意:[[]] 为引擎内部属性或方法,外部不能获取

let star = {
    name: '尼古拉斯赵四',
    girlFriend: '赵丽颖',
    age: 40
}
// 代理对象
let proxy = new Proxy(star, {
    // 取值方法
    get(target, key, receiver) {
        // 如果是重要的数据,不要访问
        if (key === 'girlFriend') {
            throw new Error('不能访问girlFriend')
        }
        if (key === 'age') {
            return 0
        }
        // target 代表 star, key 代表属性名称, receiver代表proxy, this代表Proxy的第二个参数对象
        // console.log('get', receiver === this, 11, receiver === proxy, this.num)
        return target[key]
    },
    set(target, key, value, receiver) {
        // 如果是重要的数据,不要修改
        if (key === 'girlFriend') {
            throw new Error('不能修改girlfriend')
        }
        // console.log('set', ...args, this)
        // console.log(value)
        target[key] = value;
    },
    num: 10
})
// // 修改数据
// proxy.name = '亚洲舞王'
// // 获取数据
// console.log(proxy.name)
// 修改重要数据
// proxy.girlFriend = '孙俪'
// console.log(proxy.girlFriend, star.girlFriend)
// ++star.age;
// proxy.age;
console.log(++proxy.age)


拦截方法

get(target,key,proxy) 拦截对象属性的读取

//get(target,key,proxy) 拦截对象属性的读取
    // 1 对数据做校验
    // 2 数组或者字符串的索引值做处理(负索引值)
    // 3 方法链式调用
    // 4 模拟虚拟dom创建
    // 5 configurable, writable

// 负索引值
// let arr = [1, 2, 3, 4, 5];
// let proxy =  new Proxy(arr, {
//     // 取值方法
//     get(target, key) {
//         // 如果是负索引值
//         if (key < 0) {
//             key = key % target.length + target.length;
//         }
//         return target[key]
//     }
// })
// console.log(proxy[1])
// console.log(proxy[-1])

// 链式调用
// let str = 'hello   ';
// console.log(str.trim().toUpperCase())
// console.log(str.trim.toUpperCase)
// 定义一个方法,包装字符串
// let ickt = function(val) {
//     // 返回一个代理对象
//     return new Proxy({}, {
//         fns: [],
//         // 取值方法
//         get(target, key, proxy) {
//             // 如果key是get,返回结果
//             if (key === 'get') {
//                 // console.log(this.fns)
//                 // 执行对val的处理,并返回结果
//                 // return this.fns.reduce((result, fn) => {
//                 //     return result[fn](result)
//                 // }, val)
//                 return this.fns.reduce((result, fn) => result[fn](result), val)
//             }
//             // 存储这些操作方法
//             this.fns.push(key)
//             // 为了链式调用,每次要返回receiver
//             return proxy
//         }
//     })
// }
// 使用方法,省略()
// console.log(ickt(str).trim.toUpperCase.get)
// let ickt = function(val, tools) {
//     // 返回一个代理对象
//     return new Proxy({}, {
//         fns: [],
//         // 取值方法
//         get(target, key, proxy) {
//             // 如果key是get,返回结果
//             if (key === 'get') {
//                 // console.log(this.fns)
//                 // 执行对val的处理,并返回结果
//                 // return this.fns.reduce((result, fn) => {
//                 //     return result[fn](result)
//                 // }, val)
//                 return this.fns.reduce((result, fn) => (tools || result)[fn](result), val)
//             }
//             // 存储这些操作方法
//             this.fns.push(key)
//             // 为了链式调用,每次要返回receiver
//             return proxy
//         }
//     })
// }
// // 工具方法
// let tools = {
//     toUpperCase: val => val.toUpperCase(),
//     repeat: val => val.repeat(2),
//     trim: val => val.trim(),
//     reverse: val => val.split('').reverse().join('')
// }
// // 拓展,可以传递工具集合
// console.log(ickt(str, tools).trim.repeat.reverse.toUpperCase.get)

// react jsx
// <div id="app">
//     <img src="./demo.png" alt="demo">
//     <p>爱创课堂</p>
// </div>
// React.createElement(
//     'div', 
//     { id: 'app' },
//     React.createElement('img', { src: './demo.png', alt: 'demo' }),
//     React.createElement('p', null, '爱创课堂')
// )
// 创建React库
// let React = new Proxy({}, {
//     // 取值方法
//     get(obj, name) {
//         // 返回函数
//         return function(attrs, ...children) {
//             // 创建容器元素
//             let dom = document.createElement(name);
//             // 遍历属性
//             attrs && Object.keys(attrs).forEach(key => dom.setAttribute(key, attrs[key]))
//             // 遍历子元素
//             children.forEach(item => {
//                 // 如果是文本
//                 if (typeof item === 'string') {
//                     // 添加文本节点
//                     dom.appendChild(document.createTextNode(item))
//                 } else {
//                     // 添加元素
//                     dom.appendChild(item)
//                 }
//             })
//             // 返回创建的元素
//             return dom;
//         }
//     }
// })
// // // 模拟React创建DOM元素
// let result = React.div(
//     { id: 'app' },
//     React.img({ src: './demo.png', alt: 'demo' }),
//     React.p(null, '爱创课堂')
// )
// // console.log(result)
// // 上树
// document.body.appendChild(result);

// configurable, writable
// let obj = {
//     msg: 'hello'
// }
// Object.defineProperties(obj, {
//     color: {
//         value: 'red',
//         writable: false,
//         enumerable: true,
//         configurable: true
//     },
//     num: {
//         value: 20,
//         writable: true,
//         enumerable: true,
//         configurable: false
//     }
// })
// // 代理
// let proxy = new Proxy(obj, {})
// // 不传递操作方法,此时代理对象与原对象的行为是一致的
// console.log(proxy.msg)
// proxy.msg = 'ickt';
// // console.log(proxy.msg)
// console.log(obj)
// console.log(proxy.color)
// proxy.color = 'green';
// console.log(proxy.color)
// Object.defineProperty(obj, 'num', {
//     value: 30,
//     writable: true,
//     enumerable: true,
//     configurable: true
// })
// Object.defineProperty(proxy, 'num', {
//     value: 30,
//     writable: true,
//     enumerable: true,
//     configurable: true
// })
// console.log(obj)
set(target,key,value,proxy) 拦截对象属性的设置

has(target,key) 拦截propKey in proxy 的操作, 返回布尔值

deleteProperty(target,key) 拦截delete proxy[key] 操作,返回布尔值

ownKeys(target) 拦截	
Object.getOwnPropertyNames,Object.getOwnPropertySymbols,Object.keys,返回值是个数组

getOwnPropertyDescriptor(target,key) 拦截 Object.getOwnPropertyDescriptor操作,返回属性值的描述对象

defineProperty(target,key,descripor) 拦截Object.defineProperty Object.defineProperties 操作。

preventExtensions(target) 拦截 Object.preventExtensions(不可拓展) ,返回布尔值

idExtensible(target) 拦截Object.idExtensible , 返回布尔值

Object.getPrototypeOf(target)  拦截Object.getPrototypeOf(target)  ,返回对象

Object.setPrototypeOf(target,proto)  拦截Object.setPrototypeOf(target,proto) ,返回布尔值

Object.setPrototypeOf(target)  拦截Proxy实例 并将其作为函数调用操作

Object.construct(target,args)  拦截Proxy实例 作为构造函数调用的操作
// 定义对象
// let obj = {
//     color: 'red',
//     num: 10
// }
let obj = function() {
    console.log('obj fn')
}
// 代理
let proxy = new Proxy(obj, {
    // has(target, key) 			拦截propKey in proxy 的操作,返回 个布尔值。
    // has() {
    //     console.log(arguments)
    // }
    // deleteProperty(target, key) 		拦截 delete proxy[key]的操作,返回 个布尔值。
    // deleteProperty() {
    //     console.log(arguments)
    // }
    // ownKeys(target) 			拦截Object.getOwnPropertyNames,Object.getOwnPropertySymbols,					Object.keys,返回 个数组。
    // ownKeys() {
    //     console.log(arguments)
    //     return []
    // }
    // getOwnPropertyDescriptor(target, key) 拦截Object.getOwnPropertyDescriptor操作,返回属性的描述对象。
    // defineProperty(target, key, descripor) 	拦截Object.defineProperty、 Object defineProperties操作
    // preventExtensions(target) 		拦截Object.preventExtensions (不可拓展),返回布尔值
    // isExtensible(target) 		拦截Object.isExtensible, 返回布尔值。
    // getPrototypeOf(target) 		拦截Object.getPrototypeOf,返回对象。
    // setPrototypeOf(target, proto) 	拦截Object.setPrototypeOf, 返回一个布尔值。 
    // apply(target, object, args) 		拦截Proxy实例,并将其作为函数调用的操作 
    apply() {
        console.log(arguments)
    },
    // construct( target, args) 
    construct() {
        console.log('construct', arguments)
        return {}
    }
})
// console.log('color' in proxy)
// delete proxy.color
// console.log(Object.getOwnPropertyNames(proxy))

// 执行方法
// proxy(1, 2, 3)
// proxy.call({ color:'red' }, 1, 2, 3)
// 作为构造函数
new proxy(1, 2, 3)


Proxy要点

1、当操作代理对象参数是空对象的时候,对代理对象的操作将直接映射给被代理对象(无拦截)。

let obj = {}
// 代理
let proxy = new Proxy(obj, {})
// proxy与obj行为是一致的
proxy.color = 'red'
console.log(obj)//{color:"red"}

2、Proxy对目标对象的代理,是不透明的代理,因此在无拦截的情况下,也无法保证与目标对象的行为一直。原因是在Proxy代理过程中,Proxy代理对象内部this始终指向Proxy代理对象。

// let obj = {
//     num: 10,
//     demo() {
//         console.log(this)
//     }
// }
// 代理对象, 无拦截
// let proxy = new Proxy(obj, {})
// this指向 obj
// obj.demo()  //obj
// proxy.demo() //proxy 代理对象

// map对象: 属性名称可以是任何数据类型。
// let map = new Map();
// // let map = {};
// // 类
// class Demo {
//     constructor(color) {
//         // this._color = color;
//         // map[this] = color;
//         map.set(this, color);
//     }
//     // 特性方法
//     get color() {
//         // 通过demo和proxy调用color属性,this指向不同。
//         console.log(this, map)
//         // return this._color;
//         // return map[this];
//         return map.get(this);
//     }
// }
// // 实例化
// let demo = new Demo('red');
// // 代理对象, 无拦截
// let proxy = new Proxy(demo, {})
// // this指向 obj
// console.log(demo.color);
// console.log(proxy.color);

所以代理一些实例化对象的时候会存在this问题。 3、一些源生方法,只能通过正确的this才能获取数据,此时就无法使用Proxy做代理。

// 3 一些源生方法,只能通过正确的this才能获取数据,此时就无法使用proxy做代理了
// let r = /a/;
// let proxy = new Proxy(r, {});
// // 使用
// console.log(r.test('a'))
// console.log(proxy.test('a'))

4、Proxy.revocable方法可以返回一个可取消的代理对象。 其中revoke属性可以取消proxy代理实例。 应用场景“目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问

// 4 取消代理
let obj = {
    color: 'red'
}
let { proxy, revoke } = Proxy.revocable(obj, {});
// console.log(ickt)
// 代理
console.log(proxy.color)
// 收回代理权
revoke();
// 代理失效
console.log(proxy.color)

链接: https://fly63.com/article/detial/8457

什么是在线代理ip网页代理

当我们需要大量IP进行快节奏完成业绩的时候,很多人都会想到去IP代理服务商那里购买IP代理,所以我相信很多人对于IP代理这个词已经有一定的认识了,那么还有一个词叫做:在线代理ip网页代理

centos7下搭建高匿HTTP代理

一般适用情况:1、两台都有外网IP,一台服务器请求资源通过另外一个服务器,本文重点讲第一种。2、两台服务器,其中一台服务器只有内网IP,另外一台服务器有公网和内网IP。

.Net Core/Framework之Nginx反向代理后获取客户端IP等数据探索

公司项目最近出现获取访问域名、端口、IP错误现象,通过排查发现, 之前项目一直通过Nginx自定义Headers信息来获取,但最近运维人员失误操作造成自定义Header信息丢失,造成项目拿不到对应的数据。

反向代理和内网穿透

反向代理看上去看深奥,其实不然,只是因为汉语言文化的差异导致它看上去深奥。一般反派感觉都比较厉害和神秘。要理解反向代理,我们就不得不说一下正向代理。正向代理代理的对象是客户端;反向代理代理的对象是服务端

反向代理Cloudflare加速网站(SNIproxy)

写在教程前:为什么要反向代理cloudflare?答:缩短路由,加快cloudflare节点到大陆用户的速度,用过cloudflare的用户应该知道,这家CDN的速度在除了大陆以外的地方访问都非常快,那么又没有什么办法使其对大陆访问良好呢?

ES6中的代理(Proxy)和反射(Reflection)

调用 new Proxy() 可常见代替其它目标 (target) 对象的代理,它虚拟化了目标,所以二者看起来功能一致。代理可拦截JS引擎内部目标的底层对象操作,这些底层操作被拦截后会触发响应特定操作的陷阱函数。

Vue多环境代理配置

多人协作模式下,修改代理比较麻烦,而且很容易某个开发人员会修改了vue.config.js文件后提交了。第一,很容易引起冲突。 第二,很容易出现代理错误,需要排查。而且现在微服务盛行

node.js代理访问

本地开发,代理访问,防止跨域(一般通过webpack配置代理即可),特殊情况如携带一些自定义的登录cookie则需要通过自己写node,作为一种server中间层,单线程异步可以缓解服务器压力

vue proxy代理跨域

changeOrigin的属性值为一个布尔值,如果设置为true,那么本地会虚拟一个NODE服务端接收你的请求并代你发送该请求(中间件)。[本质上是本地开了一个服务器dev-server,所有的请求都通过这里转发出去。]

Nginx反向代理之动静分离

我们已经知道了什么是正向代理与反向代理,这次我们就讲一下Nginx的动静分离的案例,其实质运用的就是反向代理,专门用一台服务器代理服务器上的图片资源。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!