ES6之Proxy

Proxy用于修改某些操作的默认行为,等同于在语言层面作出修改,所以属于一种“元编程”,即对编程语言进行编程。
Proxy可以理解成在目标对象前架设的一个“拦截”成,外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制可以对外界的访问进行过滤和改写。
proxy作用:比如vue中拦截,预警、上报、扩展功能、统计、增强对象等等
同一个拦截器函数可以设置拦截多个操作:

var handler={
	get:function(target,name){
		if(target,name){
			if(name==='prototype'){
				return Object.prototype;
			}
			return 'Hello,'+name;
		}
	},
	apply:function(target,thisBinding,args){
		return args[0];
	},
	construct:function(target,args){
		return {value:args[1]};	
	}
};
var fproxy=new Proxy(function(x,y){
	return x+y;
},handler);
fproxy(1,2);//1
new fproxy(1,2);//2
fproxy.prototype===Object.prototype//true
fproxy.foo//'Hello,foo'

new Proxy(target,hander);
let obj=new Proxy(被代理的对象,对代理的对象做什么操作)
hander:{
set(){},//设置的时候干的事情
get(){},/获取干的事情
deleteProperty(){},//删除
has(){},//有没有这个东西
apply(){}//调用处理

}
get()

var person={
	name:"远方"
}
var proxy=new Proxy(person,{
	get:function(target,property){
		if(property in target){
			return target[property];	
		}else{
			throw new ReferenceError("error");
		}
	}
});
proxy.name//"远方"
proxy.age//"error"
//如果没有拦截器,访问不存在的属性只会返回undefined 

利用get拦截实现一个生成各种DOM节点的通用函数dom

const DOM=new Proxy({},{
	get(target,property){
	//property是DOM.xxx的xxx
		return function(attr={},...children){
			const el=document.createElement(property);
			for(let key of Object.keys(attr)){
				el.setAttribute(key,attr[key]);	
			}
			for(let child of children){
				if(typeof child=='string'){
					child =document.createTextNode(child);
				}
				el.appendChild(child);
			}
			return el;
		}	
	}
});
let oDiv=DOM.div({id:'div1'},'hello','world',
				DOM.a({url},'访问'));
window.onload=function(){
	document.body.appendChild(oDiv);
}

set()
set方法用于拦截某个属性的赋值操作

let validator={
	set(target,prop,value){
		if(prop==='age'){
			if(!Number.isInteger(value)){
				throw new TypeError('年龄必须为整数');	
			}
			if(value>200){
				throw new RangeError('年龄不合法');	
			}
		}	
		target[prop]=value;
	}
}
let person=new Proxy({},validator);
person.age=210;
console.log(person.age);

apply()
apply方法拦截函数的调用、call和apply操作

function fn(){
	return '这是一个函数';
}
let proxy=new Proxy(fn,{
	apply(){
		return '函数';	
	}
})
console.log(proxy());
function sum(a,b){
return a+b;
}
let newSum=new Proxy(sum,{
	apply(target,context,args){
		return Reflect.apply(...arguments)*2;	
	}
})
console.log(newSum(2,3));

deleteProperty()和has()
deleteProperty方法用于拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除
has方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。

let json={
	a:1,
	b:2
};
let newJson=new Proxy(json,{
	deleteProperty(target,property){
		console.log(`您要删除${porperty}属性`)
		delete target[property];
	},
	has(target,property){
		console.log(`判断是否存调用has方法`);
		return property in target;
	}
});
conaole.log('a' in newJson);
delete newJson.a;
console.log(newJson);

construct()
construct方法用于拦截new命令。

var proxy=new Proxy(function (){},{
	construct:function(target,args){
		console.log('called:'+args.join(', '));
		return {value:args[0]*10};//return返回值必须是一个对象,否则会报错	
	}
});
(new proxy(1).value);
//"called:1"
//10

defineProperty()
defineProperty方法可以拦截Object.defineProperty操作

var handler={
	defineProperty(target,key,descriptor){
		return false;	
	}
};
var target={};
var proxy=new Proxy(target,handler);
proxy.foo=bar;//TypeError

getOwnPropertyDescriptor()
getOwnPropertyDescriptor方法拦截Object.getOwnPropertyDescriptor(),返回一个属性描述对象或者undefined

var handler={
	getOwnPropertyDescriptor(target,key,descriptor){
		if(key[0]==='_'){
			return;	
		}
		return Object.getOwnPropertyDescriptor(target,key);
	}
};
var target={baz:'tar'};
var proxy=new Proxy(target,handler);
Object.getOwnPropertyDescriptor(proxy,'baz');
//{value:'tar',writable:true,enumerable:true,configurable:true}

getPrototypeOf()
getPrototypeOf方法主要用来拦截获取对象的原型。

var proto={};
var proxy=new Proxy({},{
	getPrototypeOf(target){
		return proto;	
	}
});
Object.getPrototypeOf(proxy)===proto//true

isExtensible()
isExtensible方法拦截Object.isExtensible操作。

var proxy=new Proxy({},{
	isExtensible:function(traget){
		console.log("called");
		return true;	
	}
});
Object.isExtensible(proxy);
//"called"
//true

ownKeys()
ownKeys方法用来拦截对象自身属性的读取操作。

let target={
	a:1,
	b:2,
	c:3
};
let handler={
	ownKeys(target){
		return ['a'];	
	}
};
let proxy=new Proxy(target,handler);
Object.keys(proxy);//['a']

preventExtensions()
preventExtensions方法拦截Object.preventExtensions()。
这个方法有一个限制,只有目标对象不可扩展,proxy.preventExtensions才能返回true,否则会报错。

let proxy=new Proxy({},{
	preventExtensions:function(target){
		console.log('called');
		Object.preventExtensions(target);
		return true;
	}
});
Object.preventExtensions(proxy);
//"called"
//true

setPrototypeOf()
setPrototypeOf方法主要用于拦截Object.setPrototypeOf方法。

var proto={};
var proxy=new Proxy(function(){},{
	setPrototypeOf(target,proto){
		throw new Error("改变属性不合法")
	}
});
Object.setPrototypeOf(proxy,proto);
//Error:改变属性不合法

Proxy.revocable()
Proxy.revocable方法返回一个可取消的Proxy实例。

let {proxy,revoke}=Proxy.revocable({},{});
proxy.foo=123;
proxy.foo//123;
revoke();
proxy.foo//TypeError
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值