数据绑定:模型到视图
Object.defineProperty
听说vuejs和avalon都是使用这种方式实现的。
Object.defineProperty最早是由IE8实现的,但是IE8的实现有许多问题而且不能hack。。。所以vuejs才支持IE9+,avalon才使用VBScript这个鬼。
我们可以在Object.defineProperty里用getter和setter方法来定义对象的属性,这个属性叫存储器属性(JavaScript权威指南的翻译,JavaScript高级程序设计翻译为访问器属性,英文:accessor property)。当读取属性的时候,会调用getter方法,设置属性时,就会调用setter方法。
所以,setter方法就给了我们无限可能,自然就可以将数据的变化反映到视图上去。我们看一个例子(改自JavaScript高级程序设计的代码):
html,就一行:
<div id="bookName"></div>
js:
var bookName = document.getElementById('bookName') var book = { _year: 2004, edition: 1 }; Object.defineProperty(book, "year", { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; bookName.textContent = newValue; this.edition += newValue - 2004; } } }); book.year = 2005;
我们定义了一个book对象,并给了他一个year的属性,读取year的返回_year的值,设置year的时候,_year也随之变化,并且给div的textContent也赋上了新值。就这样完成了简单的模型到视图的绑定。
Object.observe
接下来我们要祭出ES7的神器了——Object.observe。
Object.observe()
,作为未来ECMAScript标准的一部分,是一个用于异步监听JavaScript对象变化的方法,并且无需使用额外的JavaScript库。它允许监听器接受一个按时间顺序排列的变更记录序列,这些变更记录描述了被监听对象所发生变化的内容的集合。
不过它的支持情况就没那么让人兴奋了(来自Can I Use):
它的使用更加简单。
还是上面的那一条html代码,js现在是这样:
var book = { year: 2004, edition: 1 }; var bookName = document.getElementById('bookName') function observer(changes) { bookName.textContent = changes[0].object[changes[0].name]; } Object.observe(book, observer) book.year = 2005;
当book的值发生变化的时候,就会触发observer函数,设置div的值。同样完成了数据到模型的绑定。
脏检查
Angular和Regular都使用了脏检查。
脏检查中,都有一个watch方法来监视着数据的变化,检测到数据变化时就会触发监听的回调,在回调里处理相应的逻辑。但是我们如何知道数据变化了呢。
这里会有一个digest方法,在这个方法里,检查新值和旧值是否相等,如果不相等,就会触发监听回调。一直循环这个过程,直到两者相等。
框架大多数情况下都会自动进入digest,同时也会暴露接口给用户,自主触发。
这里有一个简化的实现:
var Scope = function() { this.$$watchers = []; } Scope.prototype.$watch = function(watchExp, listener) { this.$$watchers.push({ watchExp: watchExp, listener: listener || function() {} }); } Scope.prototype.$digest = function() { var dirty; do { dirty = false; for(var i = 0; i < this.$$watchers.length; i++) { var newValue = this.$$watchers[i].watchExp(), oldValue = this.$$watchers[i].last; if(oldValue !== newValue) { this.$$watchers[i].listener(newValue, oldValue); dirty = true; this.$$watchers[i].last = newValue; } } } while(dirty); }
我们可以这样使用,html代码: <input type="text">
js:
var $scope = new Scope(); $scope.name = 'zjzhome'; $scope.$watch(function() { return $scope.name; }, function(newValue, oldValue) { console.log('Input value updated - it is now ' + newValue); element.value = $scope.name; }); var element = document.querySelector('input'); function updateScopeValue() { $scope.name = 'Bob'; $scope.$digest(); }; updateScopeValue();
你会发现input显示为Bob了。
这里同时也能够进行视图到模型的绑定,只要监听input的keyup事件即可:
element.onkeyup = function() { $scope.name = element.value; $scope.$digest(); }
MVVM框架中实现远比这些复杂。了解下基本的原理对于迅速的掌握框架的使用也是好的。
相关文章
- CANN训练:模型推理时数据预处理方法及归一化参数计算
- 机器学习笔记七-----------------使用Prophet(时间序列模型)预测家用电量的数据的笔记一------数据集解析
- 小样本学习(FSL):Few-shot Learning 综述【模型微调(Fine-tunning)、数据增强、迁移学习(Transfer Learning)】
- NLP-第三方库:Huggingface【非常流行的 NLP 库,用于构建、训练和部署最先进的 NLP 模型】【提供了两个主要的库:用于模型的transformers、用于数据集的datasets】
- NLP-预训练模型-2019-NLU:RoBERTa【 优化版Bert】【丢掉NSP任务;Mask改为动态;放大数据集】
- 自然语言处理-应用场景-文本分类:基于LSTM模型的情感分析【IMDB电影评论数据集】--(重点技术:自定义分词、文本序列化、输入数据批次化、词向量迁移使用)
- 对话系统-“任务型”多轮对话(二):对话状态追踪(DST)【基于规则;基于模型】【输入:当前意图和槽值对+历史槽值对;输出:State(槽值对集合)或State Vector 】【为DP做数据准备】
- Linux网络编程(二)-分层模型02:TCP/IP四层模型(应用层、传输层、网络层、链路层)【数据:发(应用层->传输层->网络层->链路层)、接(链路层->网络层->传输层->应用层)】
- 北京大学王立威教授:高校算法的突破与创新要走在数据前面
- mysql批量更新数据
- 美数科技创始人范昂:广告只是表现,“信息流+大数据”才是数字营销的未来
- 实时数据显示--SignalR实例演示
- RBAC权限模型及数据权限扩展的实践
- 优质服务从UMA大数据平台开始
- mysql source、mysqldump 导入导出数据(转)
- Salesforce将收购市场营销数据软件公司Krux
- 百分点获C轮2500万美元融资 大数据平台"数据管家"问世
- Unity引擎打包AssetBundle后模型网格数据丢失问题
- 数据有限时怎样调优深度学习模型