尤大大的vue3.0即将到来,虽然学不动了,但是还要学的啊,据说vue3.0是基于proxy来进行对值进行拦截并操作,所以es6的proxy也是要学习一下的。
proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等) --摘自mdn
proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。 --摘自阮一峰的es6入门
proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
proxy 也可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
总结来说:proxy对象就是要在目标对象上设置自定义的规则和方法,让它按照自己定义的规则去实行某些操作。
es6 原生提供 proxy 构造函数,用来生成 proxy 实例,所以可以按照构造函数创建对象的形式去实例化一个proxy对象。
var proxy = new proxy({},{}) console.log(proxy) // proxy{}
注意点:
1 实例化一个proxy对象时,必须要传两个参数对象,否则会报错:uncaught typeerror: cannot create proxy with a non-object as target or handler,不能创建没有对象的proxy对象。
2 传两个空对象时,默认的是简单声明了一个proxy实例,(好像没啥卵用……)
参数对象解释:
第一个参数:target,目标对象,是你要代理的对象.它可以是javascript中的任何合法对象.如: (数组, 对象, 函数等等)
tip:
var arr = [] var obj = {} var person = class{} var foo = function (){} console.log(person instanceof object) // true console.log(foo instanceof object) // true console.log(arr instanceof object) // true console.log(obj instanceof object) // true
第二个参数:handler,配置对象,用来定制拦截行为,对于每一个被代理的操作,需要提供一个对应的处理函数,该函数将拦截对应的操作。
proxy支持的拦截操作,有13种,使用方法可以参考
var proxy = new proxy({},handler)
这样直接代表着,拦截的对象是空的,所以直接对proxy对象进行操控。
var target = {}; var handler = { get(target,propkey,receiver){ return 'peter' } }; var proxy = new proxy(target, handler); proxy.name = 'tom'; console.log(proxy.name) // tom console.log(target.name) // undefined
上面的代码说明了:target是个空对象,但是操作了proxy,也影响不了target
ps:要使得proxy起作用,必须针对proxy实例进行操作,而不是针对目标对象进行操作
var proxy = new proxy(target,{})
handler没有设置任何拦截,那就等同于直接通向原对象。
var target = {}; var handler = {}; var proxy = new proxy(target, handler); proxy.name = 'peter'; console.log(proxy.name) // peter console.log(target.name) // peter
上面的代码说明了:handler是一个空对象,没有任何拦截效果,访问proxy就等同于访问target
proxy实例化的对象默认带有get和set方法。也可以在这些基础上进行拦截操作,其他的13种方法也是如此。
receiver:proxy实例
例子:
var person = { name: "张三" }; var proxy = new proxy(person, { get: function(target, property) { if (property in target) { return target[property]; } else { throw new referenceerror("property \"" + property + "\" does not exist."); } } }); proxy.name // "张三" proxy.age // property "age" does not exist.
参考阮一峰的例子,上述说明了,如果输入目标函数不存在的属性,就直接报错。
receiver:proxy实例本身
例子:
var target = {} var handler = { set(target, propkey, value, receiver) { if (typeof value !== 'string') { target[propkey] = string(value); }else{ target[propkey] = value; } } } var proxy = new proxy(target, handler) proxy.name = 'peter' proxy.age = 25 console.log(typeof proxy.name) // string console.log(typeof proxy.age) // string
上面例子就是拦截对象是不是字符串,不是字符串的话会强制转化为字符串。
arguments:目标对象的参数数组
例子:
var target = function(a,b){ return 10 + a + b } var handler = { apply(target,context,arguments){ arguments[0] = 10 arguments[1] = 20 return arguments.reduce(function(prev, curr, idx, arr){ return prev + curr; }); } } var proxy = new proxy(target,handler) console.log(proxy(1,2)) // 30
上面的例子,就是目标函数是要传两个参数,并且返回之和,拦截目标做的就是改变目标对象的参数,并且求和,所以这样写触发了apply方法,返回30,而不是13
key: 需查询的属性名,是一个字符串!!!!!
例子:
var target = { name: 'peter', age:25 } var handler = { has(target,key){ return key in target; } } var proxy = new proxy(target,handler) console.log('age' in proxy) // true console.log('colors' in proxy) // false
上面的例子是典型的has的方法,判断所要查询的属性名是不是在目标对象上的属性名,返回布尔值。
ps:has拦截对for...in循环不生效。
newtarget:创造实例对象时,new命令作用的构造函数
例子:
var p = new proxy(function () {}, { construct: function(target, args) { console.log('called: ' + args.join(', ')); return { value: args[0] * 10 }; } }); (new p(1)).value // "called: 1" // 10
由此可见,是针对构造函数而言的,对目标对象的构造函数进行拦截。
拓展:
object.defineproperty(),声明对象的属性,参数说明和上述一样
例子:
var obj = {} object.defineproperty(obj, "key", { enumerable: false, configurable: false, writable: false, value: "static" });
例子:
var target = { name: 'peter', age:25 } var handler = { defineproperty(target,key,descriptor){ if(key === 'color'){ throw new error('不能定义颜色') } object.defineproperty(target, key, descriptor) // return true } } var proxy = new proxy(target,handler) var descriptor = { writable : true, enumerable : true, configurable : true } descriptor.value = 'sport' object.defineproperty(proxy, 'favor', descriptor) console.log(proxy.favor) // sport descriptor.value = 'red' object.defineproperty(proxy, 'color', descriptor) // 不能定义颜色 console.log(proxy.color)
如果目标对象不可扩展(non-extensible),则defineproperty不能增加目标对象上不存在的属性,否则会报错。另外,如果目标对象的某个属性不可写(writable)或不可配置(configurable),则defineproperty方法不得改变这两个设置。
例子:
var target = { _prop: 'foo' }; var handler = { deleteproperty (target, key) { if (key[0] === '_') { throw new error(`invalid attempt to ${target} private "${key}" property`); } delete target[key]; return true; } }; var proxy = new proxy(target, handler); delete proxy._prop // error: invalid attempt to delete private "_prop" property
上面代码中,deleteproperty方法拦截了delete操作符,删除第一个字符为下划线的属性会报错。
注意,目标对象自身的不可配置(configurable)的属性,不能被deleteproperty方法删除,否则报错。
例子:
o = { bar: 42 }; d = object.getownpropertydescriptor(o, "bar"); console.log(d) // d { // configurable: true, // enumerable: true, // value: 42, // writable: true // }
例子:
var target = { _foo: 'bar', baz: 'tar' }; var handler = { getownpropertydescriptor (target, key) { if (key[0] === '_') { return; } return object.getownpropertydescriptor(target, key); } }; var proxy = new proxy(target, handler); object.getownpropertydescriptor(proxy, 'wat') // undefined object.getownpropertydescriptor(proxy, '_foo') // undefined object.getownpropertydescriptor(proxy, 'baz') // { value: 'tar', writable: true, enumerable: true, configurable: true }
上述说明:对于第一个字符为下划线的属性名会返回undefined。
例子:
function baz() {} var baz = new baz(); console.log(baz.prototype.isprototypeof(baz)); // true
例子:
var proto = {}; var obj = object.create(proto); object.getprototypeof(obj) === proto; // true
例子:
var proto = {}; var p = new proxy({}, { getprototypeof(target) { return proto; } }); object.getprototypeof(p) === proto // true上面代码中,getprototypeof方法拦截object.getprototypeof(),返回proto对象。
是个布尔值,true是可以添加,false不可以添加
例子:
let obj = { name: 'peter', age:25 } console.log(object.isextensible(obj)) // true
例子:
var p = new proxy({}, { isextensible: function(target) { console.log("called"); return true; } }); object.isextensible(p) // called
这个方法有一个强限制,它的返回值必须与目标对象的isextensible属性保持一致,否则就会抛出错误。
即:object.isextensible(proxy) === object.isextensible(target)
例子
let obj = { name: 'peter', age:25 } object.preventextensions(obj) obj.color = 'red' // object is not extensible
例子:
let proto = {例子
var handler = { setprototypeof (target, proto) { throw new error('changing the prototype is forbidden'); } }; var proto = {}; var target = function () {}; var proxy = new proxy(target, handler); object.setprototypeof(proxy, proto); // error: changing the prototype is forbidden上面代码中,只要修改target的原型对象,就会报错。
例子:
function person(){ this.name = 'peter' this.age = 26 } person.prototype={ address:"北京" } let peter=new person(); console.log(object.getownpropertynames(peter)); // ['name','age']
例子:
var obj = {}; var a = symbol("a"); var b = symbol.for("b"); obj[a] = "localsymbol"; obj[b] = "globalsymbol"; var objectsymbols = object.getownpropertysymbols(obj); console.log(objectsymbols.length); // 2 console.log(objectsymbols) // [symbol(a), symbol(b)] console.log(objectsymbols[0]) // symbol(a)
例子:
var obj = { 0: 'a', 1: 'b', 2: 'c' }; console.log(object.keys(obj)); // ['0', '1', '2']
例子之一:
var p = new proxy({}, { ownkeys: function(target) { return ['a', 'b', 'c']; } }); object.getownpropertynames(p) // [ 'a', 'b', 'c' ]
返回一个可取消的 proxy 实例
例子:
var revocable = proxy.revocable({}, { get(target, propkey) { return propkey + '啦啦啦'; } }); var proxy = revocable.proxy; console.log(proxy.foo) // foo啦啦啦 revocable.revoke(); // 执行撤销方法 console.log(proxy.foo); // uncaught typeerror: cannot perform 'get' on a proxy that has been revoked
刚开始学proxy时,都是懵逼的状态,阮一峰es6入门一开始看代码有点难度,所以我一边看一边查资料,里面关于object对象的方法居多,也顺便学习了一下,知识很多,需要日常回顾加深理解,经过查阅,对于代理模式 proxy 的作用主要体现在三个方面:1拦截和监视外部对对象的访问,2降低函数或类的复杂度,3在复杂操作前对操作进行校验或对所需资源进行管理,目前还没有大量运用,最常见的应该是拦截和监听对象的变化吧。
我把笔记放到github里了,如需要可以去看看,有什么不对的地方,欢迎指正,大家一起进步加油。
详解es6中的代理模式——proxy
mdn
[译] 实例解析 es6 proxy 使用场景
如对本文有疑问, 点击进行留言回复!!
【JavaScript笔记(一)】万丈高楼平地起 - 基本概念篇
轻松解决 org.apache.taglibs.standard.tlv.JstlCoreTLV 困惑
vert实践五——Json?Protocol Buffer?FlatBuffers?
[基于tensorflow的人脸检测] 基于神经网络的人脸检测8——验证训练好的神经网络
网友评论