建设银行不招聘网站,图片上传分享平台,优秀定制网站建设案例,温州电商网站建设Object.defineProperty
通过Object.defineProperty方法进行数据代理#xff0c; 用vm对象的属性来代理data对象的属性
方法案例 /* 此方法用于定义或修改对象属性的方法。它允许你精确地控制属性的行为#xff0c;包括属性的值、可枚举性、可配置性和可写性。 接受三个参数…Object.defineProperty
通过Object.defineProperty方法进行数据代理 用vm对象的属性来代理data对象的属性
方法案例 /* 此方法用于定义或修改对象属性的方法。它允许你精确地控制属性的行为包括属性的值、可枚举性、可配置性和可写性。 接受三个参数1 要定义属性的对象、2属性名以及一个3描述符对象。描述符对象包含了你想要定义的属性的特性。描述符对象的属性包括value: 属性的值默认为 undefined。writable: 属性是否可写默认为 false。enumerable: 属性是否可枚举默认为 false。configurable: 属性是否可配置默认为 false。*/ let person {} // 定义一个空对象Object.defineProperty(person, name, {value: ZhangSan,writable: false,enumerable: true,configurable: false,})console.log(person.name);person.name Bob // 这行代码不会修改 name 属性的值因为 writable 属性被设置为 falsefor (let key in person) {console.log(key : person[key]); // 只会输出 name: John因为 enumerable 属性被设置为 true}delete person.name; // 这行代码不会删除 name 属性因为 configurable 属性默认为 falseconsole.log(name in person); // 输出 truename 属性仍然存在于对象中观察者Observer 订阅者Watcher模式
在Observer类中递归遍历data对象对data对象中的每个属性都进行数据劫持都指定一个getter、setter。
例外的对于数组不能通过object.defineProperty()进行数据代理因为监听的数组下标变化时会出现数据错乱问题所以数组是调用数组重写的原生方法来实现响应式。
当通过vm对象修改data对象中的属性时会触发data属性的setter方法然后触发它Dep实例的notify方法进行依赖分发通知所有依赖的Watcher实例执行内部回调函数。
最后会触发renderWatcher回调会重新执行render函数重新对比新旧虚拟DOM重新渲染页面。
模拟Observer类和 watcher 工作原理
//简单的示例展示了如何使用观察者模式实现数据劫持// 观察者类class Observer {constructor(data) {this.data data;this.observe(data)}// 监听observe(obj) {// 判断是否是一个对象类型if (!obj || typeof obj ! object) {return}Object.keys(obj).forEach(key {// 拿到对象中的每一个属性console.log(obj, key, obj[key], 拿到对象中的每一个属性--------);this.defineReactive(obj, key, obj[key])// 是否有多层嵌套。this.observe(obj[key])})}// 定义对象的响应式属性的方法defineReactive(obj, key, value) {let _this this;let dep new Dep();Object.defineProperty(obj, key, {enumerable: true,configurable: true,get() {// 收集依赖if (Dep.target) {dep.addSub(Dep.target);}return value;},set(newValue) {if (newValue value) {return;}value newValue;// 通知所有订阅者dep.notify();}});}}// 代表一个依赖Dependency管理器 用于管理和通知订阅者class Dep {constructor() {this.subs [];}// 添加订阅者addSub(sub) {console.log(sub, 添加订阅者-----------);this.subs.push(sub);}// 通知订阅者notify() {this.subs.forEach(sub {sub.update();});}}// 订阅者class Watcher {constructor(vm, key, changeFunc) {this.vm vm;this.key key;this.changeFunc changeFunc;Dep.target this;this.vm[this.key]; // 触发 getter收集依赖 没有此代码 订阅者不会被添加 也不会调用update方法 Dep.target null;}update() {console.log(this.vm, this.vm[this.key], 更新中---------);// call 是函数对象的一个方法它允许你调用一个函数并指定函数内部 this 的值以及传递其他参数。this.changeFunc.call(this.vm, this.vm[this.key]);}}// 用法示例let data {name: Alice,age: 30};// 创建观察者类 观察data中数据发生变化let observer new Observer(data);// 创建 Watcher 实例 订阅者订阅data中name属性是否发生改变 并且改变的时候执行什么操作let watcher new Watcher(data, name, function (value) {console.log(Name changed:, this, value);});// 修改数据触发通知console.log(data.name, 更改前----------);data.name Bob; // 输出: Name changed: Bob