实现的步骤:
1.监听对象属性的读取与变化
Object.defineProperty() 方法会直接在对象上定义一个新的的属性,或者已经存在的属性并且返回这个属性
语法是 Object.defineProperty(obj, prop, descript)
obj: 目标对象
prop: 需要定义或修改的属性的名字
descript: 将被定义或修改的属性的描述符
描述:
这个方法精确添加或修改对象的属性,我们添加的属性是可以枚举的属性(Object.keys()/ for...in)
对象里面存在是属性描述存在的形式是:
数据描述符:拥有可写入或不可以写入的属性(相当于口令密码)
存取描述符:由一对getter-setter 函数功能来描述的属性(方法)
注意:**描述符**必须是两种形式之一,不能同时是两者。
数据描述符和存取描述符均具有以下可选键值:
1.configurable:当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,也能够被删除。默认为 false
2.enumerable:当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。默认为 false
数据描述符:
1.value:该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
2.writable:当且仅当该属性的 writable 为 true 时,该属性才能被赋值运算符改变。默认为 false。
存取描述符同时具有以下可选键值:
1.get:一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined。
2.set:一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined。
示例:
创建属性
var o = {}; Object.defineProperty(o, "a", {value : 37, writable : true, enumerable : true, configurable : true}); console.log(o.a); Object.defineProperty(o, "b", {get : function(){ /*console.log( bValue)*/ return value }, set : function(newValue){ bValue = newValue; }, enumerable : true, configurable : true}); o.b = 38;
修改属性
当属性特性(property attribute) writable 设置为false时,表示 non-writable,属性不能被修改。
var o = {}; // 创建一个新对象 Object.defineProperty(o, "a", { value : 37, writable : false }); console.log(o.a); // 打印 37 o.a = 25; // 没有错误抛出(在严格模式下会抛出,即使之前已经有相同的值) console.log(o.a); // 打印 37, 赋值不起作用。
一般的setter 和 getters
var pattern = { get: function () { return 'I alway return this string,whatever you have assigned'; }, set: function () { this.myname = 'this is my name string'; } }; function TestDefineSetAndGet() { Object.defineProperty(this, 'myproperty', pattern); } var instance = new TestDefineSetAndGet(); instance.myproperty = 'test'; // 'I alway return this string,whatever you have assigned' console.log(instance.myproperty); // 'this is my name string' console.log(instance.myname);
解题
function Observer(property) { this.data = {}; this.recursion(data); } Observer.prototype.recursion = function(obj) { var val = null; for (key in obj) { if(obj.hasOwnProperty(key)) { val = obj[val]; if(typeof val === 'object' && !!val) { new Observer(val); } this.access(key, val); } } } Observer.prototype.access = function(key, val) { Object.defineProperty(this.data, key, { enumerable: true, configurable: true, get: function () { console.log('你访问了' + key); return val }, set: function (newVal) { console.log('你设置了' + key); console.log('新的' + key + ' = ' + newVal) if (newVal === val) return; val = newVal } }) } let app1 = new Observer({ name: 'youngwind', age: 25 }); let app2 = new Observer({ university: 'bupt', major: 'computer' }); // 要实现的结果如下: app1.data.name // 你访问了 name app1.data.age = 100; // 你设置了 age,新的值为100 app2.data.university // 你访问了 university app2.data.major = 'science' // 你设置了 major,新的值为 science
多层级对象
当传入的对象是
let app1 = new Observer({ user: { name: "liangshaofeng", age: "24" }, address: { city: "beijing" } });
递归解决问题!!
function Observer(data) { this.data = data; this.recursion(this.data); } Observer.prototype.recursion = function(obj) { var val = null; for (key in obj) { if(obj.hasOwnProperty(key)) { val = obj[key]; if(typeof val === 'object' && !!val) { new Observer(val); } this.access(key, val); } } } Observer.prototype.access = function(key, val) { Object.defineProperty(this.data, key, { enumerable: true, configurable: true, get: function () { console.log('你访问了' + key); return val }, set: function (newVal) { console.log('你设置了' + key); console.log('新的' + key + ' = ' + newVal) if (newVal === val) return; val = newVal } }) } let app1 = new Observer({ user: { name: "liangshaofeng", age: "24" }, address: { city: "beijing" } }); app1.data.user.name // 你访问了 name app1.data.user.age = 100; // 你设置了 age,新的值为100
增加事件系统
// 事件系统 function Event() { this.events = {}; } Event.prototype.emit = function(attr, val, newVal) { this.events[attr] && this.events[attr].forEach(function(item){ item(val, newVal) }) } Event.prototype.on = function(attr, callback){ if(this.events[attr]){ this.events[attr].push(callback); }else{ this.events[attr] = [callback]; } } function Observer(data) { this.data = data; this.recursion(this.data); this.eventsBus = new Event(); } Observer.prototype.recursion = function(obj) { var val = null; for (key in obj) { if(obj.hasOwnProperty(key)) { val = obj[key]; if(typeof val === 'object' && !!val) { new Observer(val); } this.access(key, val); } } } Observer.prototype.access = function(key, val) { var self = this; Object.defineProperty(this.data, key, { enumerable: true, configurable: true, get: function () { console.log('你访问了' + key); return val }, set: function (newVal) { if (typeof newVal === 'object' && !!newVal) { new Observer(newVal); } console.log('你设置了' + key); console.log('新的' + key + ' = ' + newVal) self.eventsBus.emit(key, val, newVal); if (newVal === val) return; val = newVal } }) } Observer.prototype.$watch = function(attr, callback){ this.eventsBus.on(attr, callback); } let app1 = new Observer({ user: { name: "liangshaofeng", age: "24" }, address: { city: "beijing" } }); app1.data.user.name // 你访问了 name app1.data.user.age = 100; // 你设置了 age,新的值为100 app1.data.user.name = { lastName: 'liang', firstName: 'shaofeng' }; app1.data.user.name.lastName; // 这里还需要输出 '你访问了 lastName ' app1.data.user.name.firstName = 'lalala'; // 这里还需要输出 '你设置了firstName, 新的值为 lalala' var app1 = new Observer({ name: 'liujianhuan', age: 25, company: 'Qihoo 360', address: 'Chaoyang, Beijing' }) app1.$watch('age', function(oldVal, newVal){ console.log(`我的年龄变了,原来是: ${oldVal}岁,现在是:${newVal}岁了`) }) app1.$watch('age', function(oldVal, newVal){ console.log(`我的年龄真的变了诶,竟然年轻了${oldVal - newVal}岁`) }) app1.data.age = 20;
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍Vue实现双向数据绑定,包括了Vue实现双向数据绑定的使用技巧和注意事项,需要的朋友参考一下 Vue实现双向数据绑定的方式,具体内容如下 Vue是如何实现双向数据绑定的呢?答案是前端数据劫持。其通过Object.defineProperty()方法,这个方法可以设置getter和setter函数,在setter函数中,就可以监听到数据的变化,从而更新绑定的元素的值。 实现对象属性变化
本文向大家介绍Vue实现动态响应数据变化,包括了Vue实现动态响应数据变化的使用技巧和注意事项,需要的朋友参考一下 Vue是MVVM模式,即Model-View-ViewModel,通过绑定数据即可以实时改变视图显示。 比如:使用v-blink动态绑定属性 使用v-html来绑定带有标签的内容(会解析标签) 使用v-text来绑定纯文本的内容(标签会以文本的形式输出) 无论通过哪种形式绑定,都需要
1. 简介 本小节我们将介绍 Vue 中如何动态绑定样式。包括 Class 的绑定、内联样式 Style 的绑定。掌握样式绑定的多种形式是其中的重点难点。同学们可以在学完本小节之后对样式的绑定方式加以总结,再通过反复的练习来加深印象。 2. 慕课解释 操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是属性,所以我们可以用 v-bind 处理它们:只需要通过表达式计算出字符
本文向大家介绍vue 中this.$set 动态绑定数据的案例讲解,包括了vue 中this.$set 动态绑定数据的案例讲解的使用技巧和注意事项,需要的朋友参考一下 感觉网上对this.$set的讲解乱糟糟的,我来总结一下对它单个数据、对象、数组、json数据的绑定. 话不多说直接上代码: 补充:Vue 使用$set动态给数据设置属性 在实际的开发过程中,给表单元素绑定model的时候,绑定的元
本文向大家介绍vue实现的双向数据绑定操作示例,包括了vue实现的双向数据绑定操作示例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了vue实现的双向数据绑定操作。分享给大家供大家参考,具体如下: 使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试,可得到如下运行效果 感兴趣的朋友可以测试一下看看运行效果
本文向大家介绍Vue数据驱动模拟实现1,包括了Vue数据驱动模拟实现1的使用技巧和注意事项,需要的朋友参考一下 一、前言 Vue有一核心就是数据驱动(Data Driven),允许我们采用简洁的模板语法来声明式的将数据渲染进DOM,且数据与DOM是绑定在一起的,这样当我们改变Vue实例的数据时,对应的DOM元素也就会改变了。 如下: 当我们在chrome控制台,更改vm.name时,页面中的数据也