模拟Vue2中v-module数据双向绑定
<style>
#box {
margin-top: 20px;
padding: 10px 20px;
border: 1px solid salmon;
}
</style>
</head>
<body>
<input id="myInput" type="text" />
<p id="box"></p>
<script>
var data = {};
myInput.addEventListener("input", function (e) {
//事件对象
text = e.target.value;
console.log("侦听输入的值", text);
data.value = text;
});
Object.defineProperty(data, "value", {
get() {
return "";
},
set(value) {
console.log("设置的值", value);
box.innerHTML = value;//可直接用id操作dom
},
});
</script>
</body>
总结
核心:
对象: 通过 defineProperty 对对象的已有属性值的读取和修改进行劫持(监视/拦截)
数组: 通过重写数组更新数组一系列更新元素的方法来实现元素修改的劫持
Object.defineProperty(data, 'count', {
get() {},
set() {}
})
问题
对象直接新添加的属性或删除已有属性, 界面不会自动更新 this.属性.属性名="内容"
直接通过下标替换元素或更新 length, 界面不会自动更新 arr[1] = {}
解决办法:
- 对象中提前声明一个空的属性
- 数组中 this.$set( ) 手动触发set方法,更新视图
this.userArry[index]="柯南"
this.$set(this.userArry, index, this.userArry[index])
Object.defineProperty
JS中是支持面向对象编程的,也是有着对象和类这样的概念
我们常见创建对象的方法应该是这样:
var p1 ={
name:"lisi",
}
那我们Object.defineProperty这个方法有什么用呢?
这个方法接收三个参数:
1.属性所在的对象
2.属性的名字
3.一个描述符对象
属性所在的对象 属性的名字
Object.defineProperty(p1, "name",
{ configurable: false, } 一个描述符对象
)
描述符对象是什么?
是 数据属性:
1.configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为true。
2. enumerable:表示能否通过for in循环访问属性,默认值为true
3. writable:表示能否修改属性的值。默认值为true。
5. value:包含这个属性的数据值。默认值为undefined。
configurable
var p1 = {
name: "list",
}
Object.defineProperty(p1, "name", {
configurable: false,
})
console.log(p1); //{ name: 'lisi' }
delete p1.name;
console.log(p1); //{ name: 'lisi' }
这个方法设置好configurable 这个属性,delete就不能把name属性给删除掉了。
writable
var p1 = {
name: "list",
}
Object.defineProperty(p1, "age", {
writable: false,
value: 15,
})
console.log(p1);//{name: 'list', age: 15}
console.log(p1.age); //15
p1.age = 20;
console.log(p1.age); //15
然后我们给p1这个对象新加了一个age属性,并且设置成只读的。
这样我们就无法修改这个age属性了。
enumerable
var p1 = {
name: "list",
age: 15
}
Object.defineProperty(p1, "name", {
enumerable: false
})
for (var i in p1) {
console.log(i);
} // lisi
给enumerable设置为false,这样对象就不能遍历出age这个属性的值了。
数据劫持get和set方法
第三个参数除了可以是数据属性,也可以是访问器属性。
我们使用Object.defineProperty()函数来实现数据劫持,
主要是通过get和set两个方法来实现数据劫持,
当数据发生改变时触发set方法,
默认值是undefined
当读取某一个属性时,调用的是get方法。
默认值是undefined
let data1 = {
name: '小明',
age: 18
}
Object.defineProperty(data1, 'age', {
set: function (newAge) {
console.log(this.name + '现在' + newAge + '岁')
如果set被调用,则说明想要更改data1.age的值
},
get: function () {
return 19;
当通过data1访问age时,其实获取到的是data1.age
}
})
//赋值
data1.age = 18;
data1.age = 19;
data1.age = 20;
console.log(data1.age)//19
在这里看到,我们获取data1.age
的时候只能是得到19,因为本质上data1={ name: '小明', age: [Getter/Setter] }
,
也就是说我在使用data1.age
方法时候是在使用get
方法,而get方法返回值一直是19,
所以我一直获取不了最新的值。
转换思想
通过data中添加一个属性_age来变相的达到数据同步。
let data1 = {
name: '小明',
_age: 18
}
Object.defineProperty(data1, 'age', {
set: function (newAge) {
this._age = newAge
console.log(this.name + '现在' + newAge + '岁')
},
get: function () {
return this._age;
}
})
//赋值
data1.age = 18;
data1.age = 19;
data1.age = 20;
console.log(data1.age)//20
获取data1.age
的数据是最新设置的20,