概括成一句话就是:
视图更新=>数据更新,数据更新=>视图更新
通过Object.defineProperty()来实现数据劫持,这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的。
defineProperty的用法
var Book = {}
Object.defineProperty(Book, 'name', {
set: function (value) {
name = value;
console.log('你设置书名叫做:',value);
},
get: function () {
return '《' + name + '》'
}
});
Book.name = 'vue权威指南';
console.log(Book.name);
与普通obj.name的区别
configurable 是否可配置
enumerable 是否可枚举
writable 是否可修改
value 值
Object.defineProperty(obj, prop, descriptor)中descriptor的取值如下:
- configurable
当且仅当该属性的 configurable 键值为 true
时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。 默认为 false。 - enumerable
当且仅当该属性的enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。 默认为 false。
数据描述符还具有以下可选键值: - value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。 默认为 undefined。 - writable
当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。默认为 false。
存取描述符还具有以下可选键值: - get
属性的 getter 函数,如果没有 getter,则为undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。 默认为 undefined。 - set
属性的 setter 函数,如果没有 setter,则为
undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。 默认undefined。
代码示例:
const obj={};
obj.name='梦醒';
与这样定义是一样的
Object.defineProperty(obj,'name',{
value: '梦醒',
writable: true,
configurable:true,
enumerable:true,
});
实现简单版vue的过程,主要实现{{}}、v-model和事件指令的功能。
实现mvvm主要包含两个方面,数据变化更新视图,视图变化更新数据。
关键点在于data如何更新view,因为view更新data其实可以通过事件监听即可,比如input标签监听 ‘input’ 事件就可以实现了。所以我们着重来分析下,当数据改变,如何更新视图的。
数据更新视图的重点是如何知道数据变了,只要知道数据变了,那么接下去的事都好处理。如何知道数据变了,其实上文我们已经给出答案了,就是通过Object.defineProperty( )对属性设置一个set函数,当数据改变了就会来触发这个函数,所以我们只要将一些需要更新的方法放在这里面就可以实现data更新view了。
defineProperty的双向绑定
<div></div>
<input type="text">
let obj = {}
function watch(obj, name, callback) {
let value = obj.name
Object.defineProperty(obj, name, {
set(msg) {
value = msg
callback(value)
},
get() {
return value
}
})
}
function doSomething(value) {
document.querySelector('div').innerHTML = value
document.querySelector('input').value = value
}
document.querySelector('input').addEventListener('input', (e)=> {
obj['msg'] = e.target.value
})
watch(obj, 'msg', doSomething)
总结:
双向数据绑定,主要是通过Object.defineProperty中的set方法和元素的事件监听addEventListener来实现的。