vue简版源码 Observer

本文深入解析 Vue.js 的 Observer 模块,探讨如何通过数据劫持实现响应式。主要关注 `observe` 函数入口,`walk` 方法的颗粒化开发,以及 `convert` 和 `defineReactive` 函数如何为数据属性添加 getter 和 setter,确保数据变化时能触发视图更新。同时,还介绍了 Dep 类及其在数据依赖收集中的作用。
摘要由CSDN通过智能技术生成

vue简版源码 Observer篇

相关链接:MVVM篇Compile篇Watcher篇

这篇代码的入口在中间 function observe(value, vm) 的时候。

function Observer(data) {
    //在Observer实例上暂存data
    this.data = data;
    // 调用Observer 里 walk 方法 ,这里用的是颗粒化开发思想
    this.walk(data);
}

Observer.prototype = {
    walk: function(data) {
        var me = this; // 暂存this 保证this的指向正确  这里的this是 Observer 实例 
        //对data里所有的属性名进行遍历
        Object.keys(data).forEach(function(key) {
            // 调用Observer 里 convert方法 ,这里用的是颗粒化开发思想
            me.convert(key, data[key]);  // 参数一:每一项属性名 , 参数二:data中每一项的属性值
        });
    },
    convert: function(key, val) {
        // 为每个属性增加响应式 
        // 参数一:说到底还是传递过来的那个data对象,一直没变 , 
        // 参数二:每一项的属性名
        // 参数三:每一项的属性值 可能是值类型,也可能是对象的形式 
        this.defineReactive(this.data, key, val);
    },

    defineReactive: function(data, key, val) {
        //为data中所有层次的属性都创建一个dep实例 
        var dep = new Dep();
        // 递归遍历data中所有层次的属性
        // 这就是我在上面说的参数三,可能是对象形式,大家可以去下面看一下递归的终止条件 直到它不是存在并且不是object类型
        var childObj = observe(val);  

        // 为原有属性新增get和set方法(数据劫持) 
        Object.defineProperty(data, key, {
            enumerable: true, // 可枚举
            configurable: false, // 不能再define
            get: function() {
                // 在写操作的时候如果有订阅者,调用depend 方法
                if (Dep.target) {
                    dep.depend();
                }
                return val;
            },
            set: function(newVal) {
                if (newVal === val) {
                    return;
                }
                val = newVal;
                // 新的值是object的话,进行监听
                childObj = observe(newVal);
                // 通知订阅者
                dep.notify();
            }
        });
    }
};

	// 入口
function observe(value, vm) {
    //判断value是否存在或者value的数据类型是否为object(递归的终止条件)
    if (!value || typeof value !== 'object') {
        return;
    }

    return new Observer(value);
};


var uid = 0;

function Dep() { // 构造函数 挂载在 window 上
    //没创建一个dep都会给这个dep增加一个独立的标识
    this.id = uid++; // 从0开始
    this.subs = []; // 存放订阅者的容器 watcher 
}

Dep.prototype = {
    // 在 订阅者上 watcher 触发
    addSub: function(sub) {  // sub : 订阅者 watcher
        this.subs.push(sub); // 存放订阅者 watcher
    },

    depend: function() {
        // Dep.target :是订阅者 watcher  调用 watcher 里 addDep 方法,参数this是Dep 本身
        Dep.target.addDep(this);
    },

    removeSub: function(sub) {
        var index = this.subs.indexOf(sub);
        if (index != -1) {
            this.subs.splice(index, 1);
        }
    },

    //通知所有的watcher
    notify: function() {
        //遍历subs中所有的 watcher 的实例
        this.subs.forEach(function(sub) {
            // 每一个watcher的实例调用update方法
            sub.update();
        });
    }
};
// 重点!!不能忘 在Dep构造函数上定义的属性,目前是null,在 watcher.js 中用的到  
// 构造函数 挂载在window 上 在哪都能调用!!!
Dep.target = null;  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值