skill-es6中Proxy相关使用场景

背景

后端同学来找我说,op后台的一个弹框出不来了。查了一下原因,是因为没有“深入”做对象的undefined检测。类似下面这样的场景:

1
2
3
4
this.setState({
id: obj.video.id || 0, // video is undefined
visible: true,
})

后端同学返回的obj对象数据结构有问题。因此导致无法后面的visible也报错,无法弹框。

如何解决“深入”的undefined

1层: 直接“短路语法”处理比较好:

1
id: obj.id || 0

多层

2层:

1
id: obj ? obj.id : 0

3层:

1
id: obj ? (obj.video ? obj.video : 0 ) : 0

4层:

1
id: obj ? (obj.video ? (...递归) : 0 ) : 0

此时想到了什么?js中的setter和getter。再好好想想,可以想到es6中的Proxy
先写Proxy的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const noUndefined = (obj,default = {}) => {
let handlers = {
get: (target, property) => {
target[property] = (property in target) ? target[property] : default
if (typeof target[property] === 'object') {
return new Proxy(target[property], handlers)
}
return target[property]
}
}
return new Proxy(obj, handlers)
}

this.setState({
id: noUndefined(obj,0).video.id,
visible: true,
})

Proxy基础

语法:

1
var p = new Proxy(target, handler);

Proxy就是代理的意思。没有什么新意。
详细的文章
阮一峰es6-Proxy
mdn-proxy
handler对象方法的列表:

traps description
get 获取某个key值
set 设置某个key值
has 使用in操作符判断某个key是否存在
apply 函数调用,仅在代理对象为function时有效
ownKeys 获取目标对象所有的key
construct 函数通过实例化调用,仅在代理对象为function时有效
isExtensible 判断对象是否可扩展,Object.isExtensible的代理
deleteProperty 删除一个property
defineProperty 定义一个新的property
getPrototypeOf 获取原型对象
setPrototypeOf 设置原型对象
preventExtensions 设置对象为不可扩展
getOwnPropertyDescriptor 获取一个自有属性 (不会去原型链查找) 的属性描述

Proxy其它使用场景

用Proxy来包装fetch

在前端发送请求,我们现在经常用到的应该就是fetch了,一个原生提供的API。
我们可以用Proxy来包装它,使其变得更易用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
let handlers = {
get (target, property) {
if (!target.init) {
// 初始化对象
['GET', 'POST'].forEach(method => {
target[method] = (url, params = {}) => {
return fetch(url, {
headers: {
'content-type': 'application/json'
},
mode: 'cors',
credentials: 'same-origin',
method,
...params
}).then(response => response.json())
}
})
}

return target[property]
}
}
let API = new Proxy({}, handlers)

await API.GET('XXX')
await API.POST('XXX', {
body: JSON.stringify({name: 1})
})

统计函数调用次数

在做服务端时,我们可以用Proxy代理一些函数,来统计一段时间内调用的次数。
在后期做性能分析时可能会能够用上:

1
2
3
4
5
6
7
8
function orginFunction () {}
let proxyFunction = new Proxy(orginFunction, {
apply (target, thisArg. argumentsList) {
log(XXX)

return target.apply(thisArg, argumentsList)
}
})

私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
let user = {
_name : 'tim',
age: 18,
getName: function() {
returen _name
}
}

privateProp = obj => {
return new Proxy(obj,{
get(target, key, proxy) {
if(key.startsWith('_')) {
throw Error(`${key}` is no access allowed)
}
return Reflect.get(target, key, proxy);
}
set(target, key, value, proxy) {
if(key.startsWith('_')) {
throw Error(`${key}` is no access allowed)
}
return Reflect.get(target, key, value, proxy);
}
})
}

let privateUser = privateProp(user)
user._name // tim
privateUser._name // _name is no access allowed

其它

比如ng1和vue之前的双向绑定实现

参考

实例解析ES6 Proxy使用场景