const ninjaCllection={
ninjas:["tao","bo","wen"],
get firstNinja(){
console.log("Getting firstNinja");
return this.ninjas[0];
},
set firstNinja(value){
console.log("Setting firstNinja");
this.ninjas[0]=value;
}
};
if(ninjaCllection.firstNinja=="tao"){//隐式调用getter方法
console.log("tao is the first ninja");
}
ninjaCllection.firstNinja="Tao";//隐式调用setter方法
class NinjaCllection={
constructor(){
ninjas:["tao","bo","wen"];
},
get firstNinja(){
console.log("Getting firstNinja");
return this.ninjas[0];
},
set firstNinja(value){
console.log("Setting firstNinja");
this.ninjas[0]=value;
}
};
const ninjaCollection=new NinjaCllection();
if(ninjaCllection.firstNinja=="tao"){//隐式调用getter方法
console.log("tao is the first ninja");
}
ninjaCllection.firstNinja="Tao";//隐式调用setter方法
const emperor={name:"taobowen"};//emperor是目标对象
const reprentative=new Proxy(emperer,{//通过Proxy构造器创建代理,传入对象emperor,以及包含get与set方法的对象,用于处理对象属性的读写操作
get:(target,key)=>{
console.log("reading"+key+"through a proxy");
return key in target?target[key]:"don't bother the emperor";
},
set:(target, key, value) =>{
console.log("writing"+key+"thrrough a proxy");
target[key]=value;
}
});
//分别通过目标对象和代理对象访问name属性
if(emperor.name==="taobowen"){
console.log("the emperor's name is taobowen");
}
if(reprentative.name==="taobowen"){
console.log("we can get the name property through a proxy");
}
//直接访问目标对象上不存在的nickname属性将返回undefined
if(emperor.nickname===undefined){
console.log("the emperor doesn't have a nickname");
}
//通过代理对象访问时,将会检测到nickname属性不存在,并返回警告
if(reprentative.nickname==="don't bother the emperor"){
console.log("the proxy jumps in when we make inproper requests");
}
//通过代理对象添加nickname属性后,分别通过目标对象和代理对象均可访问nickname属性
reprentative.nickname="Tenno";
if(emperor.nickname==="Tenno"){
console.log("the emperor now has a nickname");
}
if(reprentative.nickname==="Tenno"){
console.log("the nickname is alse accessible through the proxy");
}
getter、setter
第一次接触getter、setter是在vue的双向绑定的类源码中,在Object.defineProperty里定义getter、setter,那时对getter、setter在发布-订阅设计模式中扮演的角色有了一个粗浅的了解。简单的来说,getter、setter可以控制对象中属性的访问,而定义getter、setter有三种方法:
在上例中我们对对象中的ninjas列表的第一个元素设置了访问的getter、setter方法,在我们通过访问firstNinja属性访问ninjas的第一个元素时,会隐式调用相关的getter、setter方法,前者在获取属性值的时候调用,不接受任何参数;后者在对属性赋值的时候调用,接受一个参数,即赋值表达式的右边部分。 好的,下面我们来看看怎样在ES6的Class中设置getter、setter:
由于对象字面量与类、getter和setter方法不是在同一个作用域中定义的,因此那些希望作为私有对象属性的变量是无法实现的。这时,我们就可以通过Object.defineProperty方法实现:
注意,与对象字面量和类中的getter和setter不同,通过Object.defineProperty创建的get和set方法,与私有skillLevel变量出于相同的作用域中。get和set方法分别创建了含有私有变量的闭包,我们只能通过get和set方法访问私有变量。 另外,顺便提一下getter、setter的一些简单应用,其他的在讲代理的时候再拓展:
代理
代理是我们通过代理控制对另一个对象的访问。可以将代理理解为通用化的setter与getter,区别是每个setter与getter仅能控制单个对象属性,而代理可用于对象交互的通用处理,包括调用对象的方法。 废话少说,上代码:
在使用内置的Proxy构造函数时,它可以接受两个参数,第一个是目标对象,在例子中是emperor,第二个是一个对象,该对象内定义了再对象执行特定行为时触发的函数。而关于定义各种对象行为的内置方法如下:
下面列举使用代理的一些常见应用:
最后,要注意的一点是,尽管使用代理可以创造性地控制对象的访问,但是大量的控制操作将会带来性能问题,因此我们还是要谨慎使用代理。