1. In vue2, data hijacking (event monitoring data changes) through Object.defineProperty() realizes two-way data binding
Object.defineProperty() :
definition:
Object.defineProperty()
method defines a new property directly on an object, or modifies an existing property of an object, and returns the object. (My own understanding: through this method, you can add properties to objects or modify existing properties, and you can monitor changes in properties)
In Vue2 we can use this method to use the data object (data)Object.defineProperty()进行监听data里面属性的变化进行双向数据绑定
2. For the usage of Object.defineProperty(), please refer to the official mdn documentation, which will not be explained here. The documentation is as follows:
Object.defineProperty() - JavaScript | MDN
3. Use Object.defineProperty()
a function to encapsulate a new property of an object and can monitor the change of this property
function objAddProperty(obj, key,value){
// 返回处理完毕的对象
return Object.defineProperty(obj,key, {
set(val) {
//属性被赋值或者被修改时该函数自动执行,函数只有一个形参,
//形参值为该属性被修改后的最新值
console.log('obj.a被修改成...'+val)
value = val
},
get(){
//属性被访问时该函数自动执行
//属性的值即为该函数的返回值
console.log('obj.a被访问...')
return value
}
})
}
//声明一个对象
let obj={}
// 为对象新增属性并进行监听该属性的变化
obj= objAddProperty(obj, 'a',1)
console.log(obj);
obj.a=666
3. Use Object.defineProperty()
a function to modify the existing properties of the object and can monitor the changes of the properties. It can also realize the hijacking of the properties without modifying the properties (data hijacking in Vue2, hijacking changes in object properties)
1. Hijack an attribute in the object
function observeKey(obj, key) {
let value = obj[key];
Object.defineProperty(obj, key, {
set(val) {
//属性被赋值或者被修改时该函数自动执行,函数只有一个形参,
//形参值为该属性被修改后的最新值
console.log('属性被修改成...'+val)
value = val
},
get(){
//属性被访问时该函数自动执行
//属性的值即为该函数的返回值
console.log('属性被访问...')
return value
}
});
}
let obj = { a: 1 };
observeKey(obj, "a");
// 读取a,触发get函数
console.log(obj.a);
// 设置a,触发set函数
obj.a = 2;
2. Hijack all properties in the object
In fact, it is to traverse the properties of the object to monitor
function observeObj(obj){
//循环对象的属性进行监听
for(let key in obj){
observeKey(obj,key)
}
}
function observeKey(obj, key) {
let value = obj[key];
Object.defineProperty(obj, key, {
set(val) {
//属性被赋值或者被修改时该函数自动执行,函数只有一个形参,
//形参值为该属性被修改后的最新值
console.log('属性被修改成...'+val)
value = val
},
get(){
//属性被访问时该函数自动执行
//属性的值即为该函数的返回值
console.log('属性被访问...')
return value
}
});
}
let obj = { a: 1,b:2 };
observeObj(obj)
// 读取a,触发get函数
console.log(obj.a);
// 设置a,触发set函数
obj.a = 2;
// 读取b,触发get函数
console.log(obj.b);
// 设置a,触发set函数
obj.b = 3;
Note: There is a flaw in the above, that is, when the attribute value is also an object, the attribute value cannot be hijacked, such as {a:1,c:{b:1}}
Solution: Determine the data type of the attribute value of the object, and determine whether recursion is required
function observeObj(obj){
//循环对象的属性进行监听
for(let key in obj){
if(obj[key] instanceof Object){
observeObj(obj[key])
}
else{
observeKey(obj,key)
}
}
}
function observeKey(obj, key) {
let value = obj[key];
Object.defineProperty(obj, key, {
set(val) {
//属性被赋值或者被修改时该函数自动执行,函数只有一个形参,
//形参值为该属性被修改后的最新值
console.log('属性被修改成...'+val)
value = val
},
get(){
//属性被访问时该函数自动执行
//属性的值即为该函数的返回值
console.log('属性被访问...')
return value
}
});
}
let obj = { a: 1,c:{b:2} };
observeObj(obj)
// 读取a,触发get函数
console.log(obj.a);
// 设置a,触发set函数
obj.a = 2;
// 读取b,触发get函数
console.log(obj.c.b);
// 设置a,触发set函数
obj.c.b = 3;
Note that the observeObj function cannot hijack the new properties of the object, but can only hijack the existing properties of the object.
Four,Object.defineProperty()的缺陷
1. In-depth monitoring requires one-time recursion (high performance consumption)
2. Unable to monitor the added and deleted properties of the object
Five, simple simulation of two-way data binding
Note: If you don’t understand this._name, you will use Object.definePropety to report an error Maximum call stack size exceeded
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="app">
<input type="text">
<p><span></span></p>
<p><button>点击修改data数据模型的name值为马云</button></p>
</div>
<script>
const button=document.querySelector("button")
const span=document.querySelector("span")
const input =document.querySelector('input')
const data={
name:'hsq'
}
input.value=data.name
span.innerText=`data数据模型的值为${data.name}`
Object.defineProperty(data,'name',{
get(){
return this._name
},
set(newValue){
input.value=newValue
this._name=newValue
span.innerText=`data数据模型的值为${newValue}`
console.log('data数据模型name属性值',newValue);
}
})
input.addEventListener("input",function(e){
console.log('输入框的值',e.target.value);
data.name=e.target.value
})
button.addEventListener("click",function(){
data.name='马云'
})
</script>
</body>
</html>