ES6学习笔记十(Proxy)
Posted усил
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES6学习笔记十(Proxy)相关的知识,希望对你有一定的参考价值。
get(target, key, receiver)
拦截对象属性的读取
target:目标对象
key:属性
receiver:proxy 实例本身
例子1:实现 get拦截器,对不属于该对象属性的抛出错误
var preson = name: "haohao"
var proxy = new Proxy(preson,
get: function(target, key, receiver)
if (key in target)
return target[key]
else
throw new ReferenceError(`Prop name $key does not exist`)
);
console.log(proxy.name) // haohao
console.log(proxy.age) // 抛出一个错误
例子2:实现一个公共的拦截器(继承)
var proxy = new Proxy(,
get: function(target, key, receiver)
if (key in target)
return target[key]
else
throw new ReferenceError(`Prop name $key does not exist`)
)
var preson = name: "haohao"
// 将 preson 的原型对象指向 proxy
preson.__proto__ = proxy;
console.log(preson.name)// haohao
console.log(preson.age) // 抛出一个错误
例子3:实现数组读取负数的索引
function createArray(arr)
var target = [...arr];
return new Proxy(target,
get: function(target, key, receiver)
var index = Number(key)
if (index < 0)
key = String(target.length + index)
return Reflect.get(target, key, receiver)
)
var arr = createArray([1, 2, 3, 4]);
console.log(arr[1]); // 2
console.log(arr[-1]); // 4
例子4:实现链式调用
var pipe = function (value)
var funcStack = [];
var proxy = new Proxy(,
get: function (target, key, receiver)
if (key === "get")
return funcStack.reduce(function (val, fn)
return fn(val)
, value)
let func = n => n;
switch (key)
case "double":
func = n => n * 2
break;
case "pow":
func = n => n * n
break;
case "reverseInt":
func = n => n.toString().split("").reverse().join("") | 0
// 往方法栈中添加方法
funcStack.push(func)
// 返回代理对象
return receiver
)
return proxy
console.log(pipe(3).double.pow.reverseInt.get) // 63
注意:当属性被配置为不可写,不可配置时,则Proxy不能修改该属性
var target = Object.defineProperties(,
foo:
value: 123,
configurable: false, // 不可配置
writable: false // 不可写
);
var proxy = new Proxy(target,
get: function(target, key)
return 'abc'
)
console.log(proxy.foo)
set(target, key, val, receiver)
拦截对象属性的设置
target:目标对象
key:属性
val:值
receiver:proxy 实例本身
例子1:实现范围及类型控制
var person = new Proxy(,
set: function(target, key, val, receiver)
if (key == "age")
if (!Number.isInteger(val))
throw new TypeError('The age is not an integer')
if (val > 200)
throw new RangeError('The age seems invalid')
target[key] = val
return true
)
person.age = 100
console.log(person.age)
person.age = 201 // 报错
person.age = "haohao" // 报错
注意:
- 如果目标对象自身的某个属性不可写,那么
set()
将不起作用 - set代理应当返回一个布尔值。严格模式下,
set()
代理如果没有返回true,就会报错。
apply(target, ctx, args)
拦截函数的调用
target:目标对象(函数)
ctx:目标对象的上下文(this)
args:参数(数组)
例子1:拦截返回指定字符串
var getStr = function() return 'I am the target'
var getStrProxy = new Proxy(getStr,
apply: function()
return 'I am the proxy'
)
console.log(getStrProxy()); // I am the proxy
例子2:将返回结果 * 2
var sum = function(left, right) return left + right
var sumProxy = new Proxy(sum,
apply: function(target, ctx, args)
// 将结果 * 2
return Reflect.apply(...arguments) * 2;
)
console.log(sumProxy(1, 2)) // 6
console.log(sumProxy.call(null, 1, 2)) // 6
has(target, key)
拦截 HasProperty 操作(即判断对象是否具有每个属性时,这个方法会生效)
target:目标对象
key:需查询的属性名
例子1:拦截 in 运算符
var obj =
_prop: '不可读取属性',
prop: '可以读取属性'
var objProxy = new Proxy(obj,
has(target, key)
if (key.charAt(0) == '_')
return false;
return key in target
)
console.log('_prop' in objProxy) // false
console.log('prop' in objProxy) // true
注意:
-
has() 方法拦截的是
HasProperty 操作
,而不是HasOwnProperty操作
,即has()
不判断属性是对象自身的属性,还是继承的属性。 -
has()
可以拦截 in 运算符,但不能拦截 for … in 循环。let student = name: '张三', score: 59 let studentProxy = new Proxy(student, has: function(target, key) if (key == 'score' && target[key] < 60) return false return target[key] ) // in 运算符 console.log('score' in studentProxy) // false // for .. in for(key in studentProxy) console.log(studentProxy[key]) // 张三 59
-
当源对象禁止扩展或者不可配置时,
has()
拦截会报错var obj = a: 10 // 禁止扩展 Object.preventExtensions(obj) var objProxy = new Proxy(obj, has: function(target, key) return false ) // TypeError: 'has' on proxy: trap returned falsish for property 'a' but the proxy target is not extensible console.log('a' in objProxy)
construct(target, args, newTarget)
拦截 new 命令
target:目标对象
args: 参数(数组)
newTarget 创建实例对象时, new 命令作用的构造函数
例子1:拦截 new 操作符
var p = new Proxy(function() ,
construct: function(target, args, newTarget)
console.log('拦截到')
return value: args[0] * 10
)
console.log(new p(1).value)
注意:
-
construct() 返回必须是一个对象
var p = new Proxy(function () , construct(target, args) return 2 ) new p() // TypeError: 'construct' on proxy: trap returned non-object ('2')
-
construct() 拦截的对象必须是函数
var p = new Proxy(, construct(target, args) return 2 ) new p() // Uncaught TypeError: p is not a constructor
-
construct() 中 this 的指向不是实例对象
var p = new Proxy(function() , construct: function(target, args) // construct: [Function: construct] console.log(this) return new target(...args) ) console.log(new p())
var handler = construct: function(target, args) console.log(this === handler); return new target(...args); let p = new Proxy(function () , handler); new p() // true
deleteProerty(target, key)
拦截 delete 操作
- target:目标对象
- key:属性
例子1:拦截删除属性
var p =
name: 'haohao',
_age: 20
var pProxy = new Proxy(p,
deleteProperty(target, key)
if (key.charAt(0) == '_')
throw new Error(`Invalid attempt to delete private "$key" property`)
delete target[key]
return true
)
delete pProxy.name
console.log(pProxy) // _age: 20
delete pProxy._age // Invalid attempt to delete private _age property
注:
- 如果抛出错误或者返回
false
,当前属性就无法被delete命令
删除 - 当源对象不可配置时, 不能被
deleteProperty()
删除,否则报错。
### defineProperty(target, key, descriptor)
拦截
Object.Object.defineProperty()
操作
- target:目标对象
- key:属性
- descriptor:配置项
例子1:拦截 defineProperty
var proxy = new Proxy(,
defineProperty (target, key, descriptor)
console.log(descriptor)
// value: 'bar', writable: true, enumerable: true, configurable: true
return false
);
proxy.foo = 'bar' // 不会生效
console.log(proxy) //
上面代码中,
defineProperty()
方法内部没有任何操作,只返回false
,导致添加新属性总是无效。 跟返回 false 无关系
注意:
- 当目标对象不可扩展时,defineProperty 不能添加目标对象上不存在的属性,否则会报错
- 如果目标对象的某个属性不可写或不可配置,则defineProperty不得改变这两个设置
getOwnPropertyDesciptor(target, key)
拦截
Object.getOwnPropertyDescriptor()
- target:目标对象
- key:属性
返回
属性描述对象
或undefined
例子1:拦截 getOwnPropertyDescriptor
var proxy = new Proxy( _foo: 'bar', baz: 'tar' ,
getOwnPropertyDescriptor (target, key)
if (key[0] === '_') return;
return Object.getOwnPropertyDescriptor(target, key);
);
console.log(Object.getOwnPropertyDescriptor(proxy, 'wat')) // undefined
console.log(Object.getOwnPropertyDescriptor(proxy, '_foo')) // undefined
console.log(Object.getOwnPropertyDescriptor(proxy, 'baz'))
// value: 'tar', writable: true, enumerable: true, configurable: true
getPrototypeOf(target)
拦截获取对象原型
Object.prototype.__proto__
Object.prototype.isPrototypeOf()
Object.getPrototypeOf()
Reflect.getPrototypeOf()
instanceof
注意:
getPrototypeOf()
返回值必须是对象或者null
,否则报错。- 目标对象不可扩展,
getPrototypeOf()
必须返回目标对象的原型对象
isExtensible(target)
拦截
Object.isExtensible()
操作
- target:目标对象
注:
-
该方法只能返回布尔值,否则返回值会被自动转为布尔值
-
它的返回值必须与目标对象的
isExtensible
属性保持一致,否则就会抛出错误。
### ownKeys(target)
来拦截对象自身属性的读取操作
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.keys()
for...in
循环
注: 有三类属性会被ownKeys()
方法自动过滤,不会返回。
- 目标对象上不存在的属性
- 属性名为 Symbol 值
- 不可遍历(
enumerable
)的属性
preventExtensions(target)
拦截
Object.preventExtensions()
。
注:该方法必须返回一个布尔值,否则会被自动转为布尔值。
setPrototypeOf(target)
来拦截
Object.setPrototypeOf()
注:该方法必须返回一个布尔值,否则会被自动转为布尔值。
Proxy.revocable()
返回一个可取消的 Proxy 实例。
let target = ;
let handler = ;
let proxy, revoke = Proxy.revocable(target, handler);
proxy.foo = 123;
proxy.foo // 123
revoke(); // 收回代理
proxy.foo; // 报错
以上是关于ES6学习笔记十(Proxy)的主要内容,如果未能解决你的问题,请参考以下文章