Vue双向绑定原理学习笔记一(Object.defineProperty)
相信大家使用vue的时候,一定不可避免地使用过vue的双向绑定,那么双向绑定的原理是啥?
一直很好奇。但一直忙于项目,现在有了时间,终于可以一探究竟了。
和很多人一样,我刚开始不知道如何下手,就直接百度了一下双向绑定原理,看到最多的字眼就是 Object.defineProperty,由此可见,这个东西应该是双向绑定的核心之一,那么本片笔记就主要记载这个
Object.defineProperty
Object大家都知道,是js中最大的那个对象,那么从这个结构上我们可以知道,defineProperty一定是Object上定义的一个方法,好,继续查,查到了该函数的结构,是这样的 Object.defineProperty(obj, prop, descriptor),首先我们先搞清楚这个函数是干嘛的,看看官方的描述 “该方法允许精确地添加或修改对象的属性。”
???添加或修改对象的属性?搞这么麻烦干嘛,我们看看我们最简单粗暴的方法
let obj = {}
obj.name =‘zzz’
obj.age = ‘10’
console.log(obj.name) // zzz
console.log(obj.age ) // 10
这样不就行了嘛,那么为什么还要多走一圈用这个函数呢,等等,大家仔细读一下这个描述,精确添加或修改有意思了。有多精确呢?我们先看一看他的参数,obj 需要定义属性的当前对象prop 当前需要定义的属性名desc 属性描述符,前两个很好理解,不过这个desc是个啥? 查!
通过Object.defineProperty()为对象定义属性,有两种形式,且不能混合使用,分别为数据描述符,存取描述符,大开眼界,原来js的学问这么深,我们一个一个来看
首先数据描述符
let Person = {}
Object.defineProperty(Person, 'name', {
value: 'jack',
writable: true // 是否可以改变
})
这个代码看起来还挺好理解,value就是Person对象中name属性的值,weitable就是是否能被改变,这就是数据描述符定义属性的方法,可以,继续!
存取描述符 --是由一对 getter、setter 函数功能来描述的属性
get:一个给属性提供getter的方法,如果没有getter则为undefined。该方法返回值被用作属性值。默认为undefined。
set:一个给属性提供setter的方法,如果没有setter则为undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认值为undefined。
作者:Weastsea链接:https://www.jianshu.com/p/8fe1382ba135
这样一解释,就不难看懂了,通过get获取,通过set设置!
let Person = {}
let temp = null
Object.defineProperty(Person, 'name', {
get: function () {
return temp
},
set: function (val) {
temp = val
}
})
两种设置方法都看完了,感觉并没有表达出 精确这两个字啊?我们再看看这些代码
configrable 描述属性是否配置,以及可否删除
enumerable 描述属性是否会出现在for in 或者 Object.keys()的遍历中
writable:是否可以改变属性的值
这样一来就能看理解了,Object.defineProperty这个函数可以给对象的属性设置这些配置,至于有哪些具体的配置就不看了,对于理解双向绑定的帮助不大。这里主要介绍一下get和set
1,get和set是方法,因为是方法,所以可以进行判断
2,get是得到,一般是要返回的;set是设置,不用返回
3,如果调用对象内部的属性,约定的命名方式是_age( 即不采用临时变量的方法)
这个set和get久厉害了,它可以实现当对象属性发生变化时,我们可以利用setter得到一个反馈
举个栗子
再提一句:get或set不是必须成对出现,任写其一就可以。如果不设置方法,则get和set的默认值为undefined
有了Object.defineProperty这个技术,我们可以实现一个简单的双向绑定效果了,代码如下
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="demo"></div>
<input type="text" id="inp">
<script>
var obj = {};
var demo = document.querySelector('#demo')
var inp = document.querySelector('#inp')
Object.defineProperty(obj, 'name', {
get: function() {
return val;
},
set: function (newVal) {//当该属性被赋值的时候触发
inp.value = newVal;
demo.innerHTML = newVal;
}
})
inp.addEventListener('input', function(e) {
// 给obj的name属性赋值,进而触发该属性的set方法
obj.name = e.target.value;
});
obj.name = 'fei';//在给obj设置name属性的时候,触发了set这个方法
</script>
</body>
</html>