JS 数据监听方法研究
2017-07-16 16:03
423 查看
之前模拟了一个在 HTML标签中通过自定义的 yjb-bind 和 yjb-model来进行数据绑定的,效果很不好。指令解析及数据绑定应该是在解析 DOM 树时做的,采用
所以,这次我直接抛弃了上来就想什么都做了的幻想,只研究数据监听,解析 DOM和数据绑定留待之后再研究~
这里参考了 Vue,Vue 中初始化的数据是在实例的 data 属性内,而初始化后数据还会在实例中保存一份,目的是为了通过 setter 设置监听。因为 setter 是在为该属性赋值时触发的,替换了默认的赋值操作,因此无法再在内部对该属性赋值,因为这样会递归调用这个 setter,然后就堆栈溢出了~但是必须把这个新的值保存起来,不然咋读取呢对吧
然后下面是设置数据监听的函数
用户进行操作的是 instance.data 中的属性,而实际保存到的是 instance._data 中的属性,通过 getter 获取 instance.data 中的属性时返回的也是 instance._data 中的属性。
可以把整段代码复制运行一下测试测试,可以看到,对 instance.data 对象内的所有属性的赋值操作,都会触发监听函数。包括对象内的属性,如
Vue 中,在 setter 方法内部,还会判断数据是否和之前的值相同,如果相同则直接 return,即不触发后续操作,减少不必要的性能浪费:
getAttribute和
querySelectorAll等方式来获取绑定的信息和元素,性能非常差,并且难以通过 person.name 这类的字符串访问到对象内的属性(Vue 好像是自己实现了一个解析路径字符串访问对象内属性的方法)。
所以,这次我直接抛弃了上来就想什么都做了的幻想,只研究数据监听,解析 DOM和数据绑定留待之后再研究~
正题
假设 instance 是一个框架的实例,里面的 data 对象就是初始化实例时的数据,可以看到,data 中有基本类型的属性,也有对象和数组。这里参考了 Vue,Vue 中初始化的数据是在实例的 data 属性内,而初始化后数据还会在实例中保存一份,目的是为了通过 setter 设置监听。因为 setter 是在为该属性赋值时触发的,替换了默认的赋值操作,因此无法再在内部对该属性赋值,因为这样会递归调用这个 setter,然后就堆栈溢出了~但是必须把这个新的值保存起来,不然咋读取呢对吧
var instance = { data: { a: 10, b: 20, obj: { c: 30, d: 40 }, arr: [10, 20, 30] } };
然后下面是设置数据监听的函数
/** * * @param saveData 实际保存的对象 * @param data 用户直接操作的对象 */ function setObserver(saveData, data) { // 获取对象的所有属性 Object.keys(data).forEach(function (key, index, arr) { // 判断类型,如果是对象则递归调用这个函数 if(typeof data[key] === 'object') { saveData[key] = {} setObserver(saveData[key], data[key]) } else { // 保存数据 saveData[key] = data[key] // 设置监听操作和获取操作 Object.defineProperty(data, key, { set (newVal) { saveData[key] = newVal; // 其他监听到数据修改后的操作,如: update(saveData, key); }, get () { return saveData[key]; } }) } }) } setObserver(instance._data = {}, instance.data)
// 瞎写的,为的是在监测到数据修改时提示一下 function update(data, key) { console.log("数据更新啦~"); console.log(data); }
用户进行操作的是 instance.data 中的属性,而实际保存到的是 instance._data 中的属性,通过 getter 获取 instance.data 中的属性时返回的也是 instance._data 中的属性。
可以把整段代码复制运行一下测试测试,可以看到,对 instance.data 对象内的所有属性的赋值操作,都会触发监听函数。包括对象内的属性,如
instance.data.obj.c = "cccccc"等,并且,
instance.data.arr[1] = "Array~~~~"这样对已有的数组元素赋值也是可以的,但是对对象或数组添加或删除元素,目前还是无法监测到的。
Vue 中,在 setter 方法内部,还会判断数据是否和之前的值相同,如果相同则直接 return,即不触发后续操作,减少不必要的性能浪费:
if (newVal === value || (newVal !== newVal && value !== value)) { return }
相关文章推荐
- js中对arry数组的各种操作小结 瀑布流AJAX无刷新加载数据列表--当页面滚动到Id时再继续加载数据 web前端url传递值 js加密解密 HTML中让表单input等文本框为只读不可编辑的方法 js监听用户的键盘敲击事件,兼容各大主流浏览器 HTML特殊字符
- 基于Microsoft SQL Server的BLOB数据的存取方法研究
- js方法实现返回多个数据
- js 方法实现返回多个数据的代码
- 数据仓库多维数据模型研究及其设计方法
- JS返回多个数据方法
- 近日探得用C++将二进制数据存储到XML文件的方法,因在研究时,未得到网上其他同仁的帮助(网上搜索了半天没有相关资料,只有DOTNET的),在这里不敢独享,给别的同仁在搜索时能够搜索到相关资料,也算是绵薄之力! )
- IFRAME弹出式窗口回发数据到父页面[调用父页JS方法并模拟调用按钮的回发事件]
- js通用数据检测方法(只完成js端大体功能,随会追加php端代码)
- js实时监听文本框状态的方法
- 关于用js(jquery)遍历由php传递过来的json数据的方法介绍
- Unity数据存储XML(+JS和C#的互调研究)
- JavaScript:全面解析Ajax跨站数据传输和iframe跨域名js调用(6种方法)
- js通用数据检测方法(只完成js端大体功能,随会追加php端代码)
- 选择TreeView控件的树状数据节点的JS方法(jquery)
- 近日探得用C++将二进制数据存储到XML文件的方法,由于在研究时,未得到网上其他同仁的帮助(网上搜索了半天没有相关资料,只有.NET的),在这里不敢独享,给别的同仁在搜索时能够搜索到相关资料,也算是绵薄之力! )
- flash与后台数据交换方法整理4-XMLSocket篇(转载):有点意思,有时间研究下
- .Net Remoting的效能研究学习:数据压缩方法
- IFRAME弹出式窗口回发数据到父页面[调用父页JS方法并模拟调用按钮的回发事件]
- 基于Microsoft SQL Server的BLOB数据的存取方法研究