ES5中的双向绑定
ES5中的对象属性类型有两种:分别是数据属性和访问器属性
一,数据属性
数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有4个描述其行为的特性
1,configurable:表示能否通过delete删除属性而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性;如果设置为true表示可以删除,如果是false不能被删除,默认为false
//为false的情况下无法删除
const obj={
name:"张三"
}
Object.defineProperty(obj,'name',{
configurable:false
})
delete obj.name
console.log(obj.name)//张三
//为true的情况下可以删除
const obj={
name:"张三"
}
Object.defineProperty(obj,'name',{
configurable:true
})
delete obj.name
console.log(obj.name)//undefined
2,Enumerable:表示能否通过for-in循环返回属性;设置为true可以被枚举,设置为false,不能被枚举,默认为false
//为false无法被枚举
const obj={
name:"张三",
}
Object.defineProperty(obj,'name',{
enumerable:false
})
for(let key in obj){
console.log(obj[key]) //无任何输出
}
//为true可以被枚举
const obj={
name:"张三",
}
Object.defineProperty(obj,'name',{
enumerable:false
})
for(let key in obj){
console.log(obj[key])//张三
}
3,Writable:表示能否修改这个属性的值;设置为true可以被重写,设置为false,不能被重写,默认为false
//默认不能重写
const obj={}
Object.defineProperty(obj,'name',{
value:'张三'
})
console.log(obj.name)//张三
obj.name='李四'
console.log(obj.name)//张三
//设置为true可以重写
const obj={}
Object.defineProperty(obj,'name',{
value:'张三',
writable:true
})
console.log(obj.name)//张三
obj.name='李四'
console.log(obj.name)//李四
4,value:包含这个属性的值;
const obj={
name:'张三'
}
Object.defineProperty(obj,'name',{
value:'李四'
})
//改变obj.name的值为李四,输出来李四
console.log(obj.name)//李四
//如果没有设置值,还是返回原来的值
const obj={
name:'张三'
}
Object.defineProperty(obj,'name',{})
console.log(obj.name)//张三
要修改属性的默认特性,必须使用ES5中的Object.defineProperty()方法,这个方法接收三个参数,属性所在的对象,属性的名字和一个描述符对象,描述符对象的属性就是上面的4个
二,访问器属性
访问器属性不包含数据值,它们是一对getter和setter函数,在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值。这个函数负责如何处理数据。访问器属性有4个特性 configurable和Enumerable(这两个属性和上面的用法相同)
1,Get:在读取属性时调用函数:默认为undefined
2,Set:在写入属性时调用函数:默认为undefined
注意:使用访问器属性中 getter或 setter方法,不能使用 writable 和 value 这两个配置项
const obj={}
let age=20
Object.defineProperty(obj,'age',{
get:function () {
console.log("读取属性值的时候调用")
return age
},
set:function (newValue) {
console.log("写入属性值的时候调用")
age=newValue
}
})
console.log(obj.age)//20
//设置了属性值会调用set方法
obj.age=30
console.log(obj.age)//30
实现一个小案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" id="demo">
<div id="test">test</div>
</body>
<script>
const obj={}
//用于设置obj的属性值为name
Object.defineProperty(obj,'name',{
//获取到设置set的值
//读取到obj.name属性值的更改
set:function(value){
document.getElementById('test').innerHTML=value
}
})
console.log(obj.name)
//获取到文本框中的值并赋给obj.name
document.getElementById('demo').oninput=function (e) {
obj.name=e.target.value
}
</script>
</html>
三,定义多个属性
Object.defineProperties()方法一次设置或修改多个属性。这个方法接受两个对象参数:第一个对象是要添加和修改其属性的对象,第二个对象的属性与第一个对象中要添加或修改的属性一一对应。
const obj4={
_name:"王五",
_age:33
}
Object.defineProperties(obj4,{
age:{
get(){
console.log("监听到读取age属性")
return this._age
},
set(value){
console.log("监听到设置age属性")
this._age=value
return this._age
}
},
name:{
get(){
console.log("读取到name属性")
return this._name
},
set(value){
console.log("监听到正在设置name属性")
this._name=value
return this._name
}
}
})
console.log(obj4.age,obj4.name)//33 王五
obj4.age=34
obj4.name="哈哈"
console.log(obj4.age,obj4.name)//34 '哈哈'
四,读取属性的特性
es5中Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符,这个方法接受两个参数;属性所在的对象和要读取其描述符的属性名称。返回值是一个对象,如果是访问器属性,这个对象的属性性有configurable,enumerable,get,set;如果是数据属性,这个对象的属性有configurable,enumerable,writable,value
const obj2={
name:30
}
const descriptor=Object.getOwnPropertyDescriptor(obj2,'name')
console.log(descriptor)//是一个对象,包含如下特性
ES6中的双向绑定代理(Proxy)和反射(Reflect)
ES6新增的代理和反射为开发者提供了拦截并向基本操作嵌入额外行为的能力。具体说可以给一个目标对象定义一个关联的代理对象,而这个代理对象可以作为抽象的目标对象来使用。在对目标对象的各种操作影响目标对象之前,可以在代理对象中对这些操作加以控制。
一,创建代理
要创建代理需要使用Proxy构造函数,它接受两个参数,目标对象和处理程序对象。
let Person={
name:"张三",
age:18
}
let handle={}
let P1 = new Proxy(Person,handle)
console.log(Person)//{name: '张三', age: 18}
console.log(P1)//Proxy(Object) {name: '张三', age: 18}
这时候无论是给目标属性赋值,还是给代理属性赋值都会反映在两个对象上。修改代理属性会同步反映到目标对象上。hasOwnProperty()方法在两个地方,返回的结果都相同。
//修改代理属性P1
let Person={
name:"张三",
age:18
}
let handle={}
let P1 = new Proxy(Person,handle)
P1.name="李四"
console.log(Person.name)//李四
console.log(P1.name)//李四
//修改目标属性
let Person={
name:"张三",
age:18
}
let handle={}
let P1 = new Proxy(Person,handle)
Person.name="李四"
console.log(Person.name)//李四
console.log(P1.name)//李四
//hasOwnProperty()方法在两个地方,返回的结果都相同
console.log(Person.hasOwnProperty('name'))//true
console.log(P1.hasOwnProperty('name'))//true
注意:Proxy.prototype是undefined因此不能使用instanceof操作符
二,set()方法的使用
set陷阱接受四个参数
1,trapTarget:用于接收属性(代理的目标)
2,key要写入的属性键
3,value被写入的属性值
4,receiver操作发生的对象
使用set陷阱检查传入的值是否是number类型的
let target={
name:"张三"
}
let p1=new Proxy(target,{
set(trapTarget,key,value,receiver){
console.log("正在添加属性")
if(!trapTarget.hasOwnProperty(key)){
if(isNaN(value)){
throw new TypeError("属性必须是数字")
}
}
//添加属性
return Reflect.set(trapTarget,key,value,receiver)
}
})
//当属性被添加之后
p1.count=1
console.log(target.count)//1
console.log(p1.count)//1
//如果添加属性为字符串,则给出对应的提示
p1.height="1米八"
console.log(p1.height)
以上代码定义了一个代理来验证添加到target的新属性,当执行p1.count=1时,检测到添加属性,set被调用,此时trapTarget值等于target,key为count,value等于1,receiver等于proxy。然后根据传入的value值进行判断,并给出对应的反馈。
未完待续...