双向数据绑定是非常重要的特性 —— 将js模型与html视图对应,能减少模板编译时间同时提高用户体验。我们将学习在不使用框架的情况下,使用原生js实现双向绑定 —— 一种为Object.observe(译注:现已废弃,作者写博客时为14年11月),另一种为覆盖get / set。PS: 第二种更好,详情请参阅底部的TL;DR(译注:too long;don't read. 直译为“太长,不想看”,意译为“简单粗暴来吧”)。
Object.observe()是一种新特性,其在ES7中实现,但在最新的Chrome中已可用 —— 允许对JS对象进行响应式更新。简单说就是 —— 只要对象(的属性)发生变化就调用回调函数。
一般用法为:
log = console.log
user = {}
Object.observe(user, function(changes){
changes.forEach(function(change) {
user.fullName = user.firstName + " " + user.lastName;
});
});
user.firstName = 'Bill';
user.lastName = 'Clinton';
user.fullName // 'Bill Clinton'
这很方便,且能实现响应式编程 —— 保证所有内容都是最新的。
如下:
//<input id="foo">
user = {};
div = $("#foo");
Object.observe(user, function(changes){
changes.forEach(function(change) {
var fullName = (user.firstName || "") + " " + (user.lastName || "");
div.text(fullName);
});
});
user.firstName = 'Bill';
user.lastName = 'Clinton';
div.text() //Bill Clinton
如上,我们自己实现了模型到数据的绑定!封装一下(译注:此处原文为Let’s DRY ourselves with a helper function. DRY即 don't repeat yourself):
//<input id="foo">
function bindObjPropToDomElem(obj, property, domElem) {
Object.observe(obj, function(changes){
changes.forEach(function(change) {
$(domElem).text(obj[property]);
});
});
}
user = {};
bindObjPropToDomElem(user,'name',$("#foo"));
user.name = 'William'
$("#foo").text() //'William'
换一种方式 —— 将DOM元素与JS值绑定起来。简单的方法是使用jQuery.change
//<input id="foo">
$("#foo").val("");
function bindDomElemToObjProp(domElem, obj, propertyName) {
$(domElem).change(function() {
obj[propertyName] = $(domElem).val();
alert("user.name is now "+user.name);
});
}
user = {}
bindDomElemToObjProp($("#foo"), user, 'name');
//enter 'obama' into input
user.name //Obama.
简直不要太方便,在实际开发时,可以将两者结合,通过函数来创建一个双向数据绑定:
function bindObjPropToDomElem(obj, property, domElem) {
Object.observe(obj, function(changes){
changes.forEach(function(change) {
$(domElem).text(obj[property]);
});
});
}
function bindDomElemToObjProp(obj, propertyName, domElem) {
$(domElem).change(function() {
obj[propertyName] = $(domElem).val();
console.log("obj is", obj);
});
}
function bindModelView(obj, property, domElem) {
bindObjPropToDomElem(obj, property, domElem)
bindDomElemToObjProp(obj, propertyName, domElem)
}
注意:在双向绑定时,需正确进行DOM操作,因为不同的DOM元素(input,div,textarea,select)有不同的取值方式(text,val)。同时注意:双向数据绑定并不是必须的 —— “输出型”元素一般不需要视图到模型的绑定,而“输入型”元素一般不需要模型到视图的绑定。
下面为第二种方式:
上面的解决方法并不完美。比如直接的修改并不会自动触发jQuery的“change”事件 —— 例如,直接通过代码对DOM进行修改,比如以下代码不起作用:
$("#foo").val('Putin')
user.name //still Obama. Oops.
现在,我们来用一种更激进的方式实现 —— 重写getter和setter。因为我们不仅要监测变化,我们将重写JS最底层的功能,即get/setting变量的能力,所以不那么“安全”。后面我们将会看到,这种元编程的方式有多强大。
那么,如果我们可以重写get和set对象值的方法会怎么样呢?这也是数据绑定的实质。用 Object.defineProperty() 即可实现.
其实,以前就有已废弃且非标准实现方式,但通过Object.defineProperty的实现方式更好(最重要的是标准),如下所示:
user = {}
nameValue = 'Joe';
Object.defineProperty(user, 'name', {
get: function() { return nameValue },
set: function(newValue) { nameValue = newValue; },
configurable: true //to enable redefining the property later
});
user.name //Joe
user.name = 'Bob'
user.name //Bob
nameValue //Bob
现在user.name是nameValue的别名。但可做的不仅仅是创建新的变量名 - 我们可以通过它来保证模型和视图的一致。如下:
//<input id="foo">
Object.defineProperty(user, 'name', {
get: function() { return document.getElementById("foo").value },
set: function(newValue) { document.getElementById("foo").value = newValue; },
configurable: true //to enable redefining the property later
});
user.name现在绑定到#foo元素。这种底层的方式非常简洁 —— 通过定义(或扩展)变量属性的get / set实现。由于实现非常简洁,因此可以根据情况轻松扩展/修改代码 —— 仅绑定或扩展get / set中的一个,比如绑定其他数据类型。
可封装如下:
function bindModelInput(obj, property, domElem) {
Object.defineProperty(obj, property, {
get: function() { return domElem.value; },
set: function(newValue) { domElem.value = newValue; },
configurable: true
});
}
使用:
user = {};
inputElem = document.getElementById("foo");
bindModelInput(user,'name',inputElem);
user.name = "Joe";
alert("input value is now "+inputElem.value) //input is now 'Joe';
inputElem.value = 'Bob';
alert("user.name is now "+user.name) //model is now 'Bob';
注意:上面的domElem.value只对input元素有效。(可在bindModelInput中扩展,对不同的DOM类型使用对应的方法来设置它的值)。
思考:
(译注:SPOT简单翻译为“单点原则”,即引起变化最好的是由单一入口引起的,而不是由多个入口引起的,比如一个函数,其返回结果最好仅由参数决定,这样输入和输出才能一致,而不会由于其他变化导致用一个输入会出现不同的输出)
这种自己实现的数据绑定方法与Knockout或Angular等框架的数据绑定相比,有一些优点,例如:
缺点是由于不是真正的绑定(没有脏检查),有些情况会失败 —— 视图更新时不会触发模型中的数据,所以当试着同步视图中的两个DOM元素时将会失败。也就是说,将两个元素绑定到同一个模型上时,只有更新模型,则两个元素才会被正确更新。可以通过自定义一个更新函数来实现:
//<input id='input1'>
//<input id='input2'>
input1 = document.getElementById('input1')
input2 = document.getElementById('input2')
user = {}
Object.defineProperty(user, 'name', {
get: function() { return input1.value; },
set: function(newValue) { input1.value = newValue; input2.value = newValue; },
configurable: true
});
input1.onchange = function() { user.name = user.name } //sync both inputs.
当需要使用原生JS创建模型和视图的双向数据绑定时,如下:
function bindModelInput(obj, property, domElem) {
Object.defineProperty(obj, property, {
get: function() { return domElem.value; },
set: function(newValue) { domElem.value = newValue; },
configurable: true
});
}
//<input id="foo">
user = {}
bindModelInput(user,'name',document.getElementById('foo')); //hey presto, we now have two-way data binding.
感谢阅读,本文也发布在 JavaScript Weekly, 可在reddit回复我
翻译来源: 原生JS数据绑定
原文出处 native_javascript_data_binding
主要是用Object.defineProperty实现类似vue的数据绑定。输出的data.name 并不是tom,而是name被读取了,因为defineProperty对data的name字段进行的监听劫持,修改了,name字段本应该返回的值。
在计算机语言中常用的进制有二进制、八进制、十进制和十六进制,十进制是最主要的表达形式。对于进制,有两个基本的概念:基数和运算规则。
想让数据变得更好看?不必成为经验丰富的数据科学家,也不必成为平面设计师。有一些能让数据从简单的表格变成多种多样的图形,地图甚至词“云”。并不是所有的工具都适合你,但这些工具确实很有用
Mock.js 是一款前端开发中拦截Ajax请求再生成随机数据响应的工具.可以用来模拟服务器响应. 优点是非常简单方便, 无侵入性, 基本覆盖常用的接口数据类型.大概记录下使用过程, 详细使用可以参见Mock文档 Mock Wiki
!!一般用来将后面的表达式转换为布尔型的数据(boolean) 因为javascript是弱类型的语言(变量没有固定的数据类型)所以有时需要强制转换为相应的类型
HTTP无状态协议,是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
数据绑定最早是被 Angular、Backbone 和 Ember 等框架推广而流行开来的,现在则在某种程度上是编写视图的标准途径。它能让“视图作为数据的函数”,意味着每当某些数据发生变化时,相关视图将“自动”更新。
XML是标准通用标记语言 (SGML) 的子集,非常适合 Web 传输。XML 提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。 这篇文章主要介绍Js中实现XML和String相互转化
我们在组件钩子函数computed中定义的,都属于这种类型,每一个 computed 属性,最后都会生成一个对应的 watcher 对象,但是这类 watcher 有个特点:当计算属性依赖于其他数据时,属性并不会立即重新计算
在js中我们直接这样写typeof obj===‘object’有什么问题呢?发现Array, Object,null都被认为是一个对象了。如何解决这种情况,能保证判断obj是否为一个对象
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!