Vue2源码分析-day1

初始化数据

vue中最核心的我们都知道那就是响应式数据,数据的变化视图自动更新。那么我们来new一个我们自己的vue

index.html文件下加入如下代码,这也是vue最常见的基本结构。data已经有了下面我们来获取data的数据

 <script src="./vue.js"></script>
 <script>
    const vm=new MVue({
         data(){
             return{
                 name:"zhangsan",
                 age:"16"
             }
         }
    })
 </script>

首先我们在src/main.js文件下加入如下代码

// 创建MVue构造函数
function MVue(options) {      // options就是我们接受到用户的选项,选项式api
    
}

// 将构造函数导出
export default MVue

为了更能的扩展功能和方便维护,我们需要一个专门做初始化的方法。所以我们在src下创建init.js文件加入如下代码

export function init(MVue){
    // 给MVue原型对象上挂载_init()方法
    MVue.prototype._init = function(options){

    }
}

main.js文件下如果这个方法,并且调用

import { init } from "./init"

// 创建MVue构造函数
function MVue(options) {      // options就是我们接受到用户的选项,选项式api
    // 当vue被new的时候调用_init()方法
    this._init(options)
}

init(MVue)

// 将构造函数导出
export default MVue

下面我们就可以写我们的初始化方法了,init.js文件下加入如下代码。可能你会好奇这个init_state()方法是那里的。由于用户选项有很多比如data,watch,computed…所以我们最好创建一个文件统一管理。在src文件下创建state.js文件

import { init_state } from "./state"

export function init(MVue){
    // 给MVue原型对象上挂载_init()方法
    MVue.prototype._init = function(options){

        // 在用户选项挂载到实例上
        const vm=this
        vm.$options=options

        // 初始化状态
        init_state(vm)
    }
}

state.js文件下加入如下代码

export function init_state(vm){
    // 获取实例上挂载的选项
    const opts=vm.$options;

    // 选项上如果存在data初始化data
    if(opts.data){
        init_data(vm);
    }
}
function init_data(vm){
    let data=vm.$options.data;

    // 判断data是对象还是函数并且重新赋值
    data=typeof data==='function'?data.call(vm):data;

    console.log(data);
}

到这里,输入打包命令打开index.html如果在游览器下看到如下图所示,我们就成功获取到了data里面的数据

pnpm run build

在这里插入图片描述


实现对象的响应式原理

下面我们首先来实现只有一层对象的数据劫持。state.js文件下加入如下代码

import { observe } from "./observe/index";

export function init_state(vm){
    // 获取实例上挂载的选项
    const opts=vm.$options;

    // 选项上如果存在data初始化data
    if(opts.data){
        init_data(vm);
    }
}
function init_data(vm){
    let data=vm.$options.data;

    // 判断data是对象还是函数并且重新赋值
    data=typeof data==='function'?data.call(vm):data;

    // 将data劫持重新定义data
    observe(data)
}

src文件下创建observe/index.js文件并且加入如下代码

class Observer {
    constructor(data) {
        /* 
            这里注意,Object.defineProperty只能劫持已经存在的属性,新增或删除的无法劫持
            这也是为什么vue2中新增了,$set和$delete方法这类方法的原因
        */
        this.walk(data)
    }
    walk(data) {
        // 循环对象keys依次劫持,重新定义属性
        Object.keys(data).forEach(key => {
            define_reactive(data, key, data[key])
        })
        
        // 这里重新定义data后我们打印看下data是否都加入了get和set方法
        console.log(data);
    }

}

// 这里会存在一个闭包,get和set方法存放了函数外部的变量value
export function define_reactive(data, key, value) {
    Object.defineProperty(data, key, {
        get() {
            return value
        },
        set(newValue){
            if(value!=newValue){
                value=newValue
            }
        }
    })
}


export function observe(data) {

    // 对对象劫持
    if (typeof data !== 'object' || data === null) {
        return;
    }

    // 如果一个对象被劫持过就不需要再次劫持,我们可以通过一个观察类判断是否被劫持过
    return new Observer(data)
}

如果你的游览器打印了如下图所示,那么恭喜你只有一层对象的data你重新定义完成了

在这里插入图片描述
说起data,vue2中一直有个属性_data属性。这上面挂载了我们所有在data中定义的属性。下面我们来实现它

state.js文件下修改如下代码。没错就是这么简单要加入vm._data=data这行代码就完成了。由于这是引用值。所有对data的修改也会影响到_data

function init_data(vm){
    let data=vm.$options.data;

    // 判断data是对象还是函数并且重新赋值
    data=typeof data==='function'?data.call(vm):data;

    // 实例上挂载_data
    vm._data=data

    // 将data劫持重新定义data
    observe(data)
}

下面我们在index.html下打印vm看看是否有我们的_data属性

在这里插入图片描述

到这里,其实我们的_data属性并不完美,你通过vm获取属性的时候发现每次都要加上_data,
vm._data.name。但是vue2中并不是这样的而是直接vm.name就可以获取并且修改。下面我们来解决这个问题

state.js文件下加入如下代码。我们将将vm._data代理给vm就可以解决这个问题

function proxy(vm,source,key){
    Object.defineProperty(vm,key,{
        get(){
            return vm[source][key]
        },
        set(newValue){
            if(vm[source][key]!=newValue){
                vm[source][key]=newValue;
            }
        }
    })
}

function init_data(vm){
    let data=vm.$options.data;

    // 判断data是对象还是函数并且重新赋值
    data=typeof data==='function'?data.call(vm):data;

    // 实例上挂载_data
    vm._data=data

    // 将data劫持重新定义data
    observe(data)

    // 将vm._data代理给vm
    for(let key in data){
        proxy(vm,'_data',key)
    }
}

下面我们在看我们的vm实例会发现多了name和age属性。并且可以通过vm访问到和修改

在这里插入图片描述
到这里不知你们还记得我们最早说过的,这只是一个只有一层对象的数据劫持。如果多层就代理不到了
我们修改index.html代码如下

       const vm=new MVue({
            data(){
                return{
                    name:"zhangsan",
                    age:"16",
                    address:{
                        city:"地球村    "
                    }
                }
            }
       })
       console.log(vm);

在游览器上。我们会看到address并且没有get和set方法。下面我们来解决这个问题

在这里插入图片描述

observe/index.js文件下修改如下代码

// 这里会存在一个闭包,get和set方法存放了函数外部的变量value
export function define_reactive(data, key, value) {
    observe(value)		// 递归调用我们的observe方法

    Object.defineProperty(data, key, {
        get() {
            return value
        },
        set(newValue){
            if(value!=newValue){
                value=newValue
            }
        }
    })
}

再次看我们的address就会发现get和set方法已经出现了。这说明我们的多级对象代理已经完成了

在这里插入图片描述

用户可能会存在这样的赋值,现在我们是没办法办法代理到的

const vm = new MVue({
    data() {
        return {
            name: "zhangsan",
            age: "16",
           
        }
    }
})
vm.address = {
    city: "地球村"
}

所以我们在observe/index.js文件下define_reactive方法中的set修改如下。如果直接通过vm赋值对象,给这些属性同样代理

set(newValue){
    if(value!=newValue){
        observe(newValue)
        value=newValue
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/65042.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[openCV]基于拟合中线的智能车巡线方案V3

import cv2 as cv import os import numpy as np# 遍历文件夹函数 def getFileList(dir, Filelist, extNone):"""获取文件夹及其子文件夹中文件列表输入 dir&#xff1a;文件夹根目录输入 ext: 扩展名返回&#xff1a; 文件路径列表"""newDir d…

『Samba』在Linux中实现高效访问和管理共享文件夹的基本操作与实践

&#x1f4e3;读完这篇文章里你能收获到 Samba 的安装和配置&#xff1a;详细介绍了如何在 Linux 操作系统上安装和配置 Samba 服务器共享文件夹的设置&#xff1a;指导如何选择要共享的文件夹&#xff0c;并为其设置共享名称、路径以及访问权限Samba 用户的创建&#xff1a;提…

C# App.config和Web.config加密

步骤1&#xff1a;创建加密命令 使用ASP.NET提供的命令工具aspnet_regiis来创建加密命令。 1、打开控制台窗口&#xff0c;在命令行中输入以下命令&#xff1a; cd C:\Windows\Microsoft.NET\Framework\v4.xxxxx aspnet_regiis.exe -pef connectionStrings "C:\MyAppFo…

搭建 elasticsearch8.8.2 伪集群 windows

下载windows 版本 elasticsearch8.8.2 以下链接为es 历史版本下载地址&#xff1a; Past Releases of Elastic Stack Software | Elastic windows 单节点建立方案&#xff1a; 下载安装包 elasticsearch-8.8.2-windows-x86_64.zip https://artifacts.elastic.co/download…

代码随想录算法训练营第51天|动态规划part09|198.打家劫舍、213.打家劫舍II、337.打家劫舍III

代码随想录算法训练营第51天&#xff5c;动态规划part09&#xff5c;198.打家劫舍、213.打家劫舍II、337.打家劫舍III 198.打家劫舍 198.打家劫舍 思路&#xff1a; 仔细一想&#xff0c;当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。 所以这里就更感觉到&a…

机器学习鱼书笔记(自用更新)

零、预知识 1.Numpy 使用 介绍&#xff1a;高效的操作多维数组的函数库。 安装&#xff1a;&#xff08;前提已经安装了python&#xff09; pip install numpy导入 import numpy as np创建数组 Numpy最重要的数据结构是多维数组&#xff08;ndarray&#xff09;。通过Numpy&…

农商行基于分类分级的数据安全管控建设实践

《数据安全法》颁布实施以来&#xff0c;以分类分级为基础&#xff0c;对数据进行差异化管理和防护&#xff0c;成为行业共识。 金融行业作为数据密集的高地&#xff0c;安全是重中之重&#xff0c;而鉴于金融数据种类和内容庞杂&#xff0c;面临规模化用数、普惠用数、跨机构共…

分布式协议与算法——Paxos算法

目录 Paxos算法Basic Paxos算法三种角色如何达成共识&#xff08;协商过程&#xff09;小结&#xff1a; Multi-Paxos算法关于 Multi-Paxos 的思考领导者优化Basic PaxosChubby 的 Multi-Paxos 实现小结 参考 Paxos算法 Paxos论文 Paxos Made Simple 、author&#xff1a;Lesli…

wireshark 安装和使用

wireshark&#xff0c;世界上最受欢迎的网络协议分析器。是一个网络流量分析器&#xff0c;或“嗅探器”&#xff0c;适用于Linux、macOS、*BSD和其他Unix和类Unix操作系统以及Windows。它使用图形用户界面库Qt以及libpcap和npcap作为数据包捕获和过滤库。 wireshark&#xff…

Flamingo

基于已有的图像模型和文本模型构建多模态模型。输入是图像、视频和文本&#xff0c;输出是文本。 Vision encoder来自预训练的NormalizerFree ResNet (NFNet)&#xff0c;之后经过图文对比损失学习。图片经过图像模型的输出是2D grid&#xff0c;视频按1FPS的频率采样后经过图…

【2种方法,jmeter用一个正则提取器提取多个值!】

jmeter中&#xff0c;用json提取器&#xff0c;一次提取多个值&#xff0c;这个很多人都会。但是&#xff0c;用正则提取器一次提取多个&#xff0c;是否可以呢&#xff1f; 肯定&#xff0c;很多人都自信满满的说&#xff0c;可以&#xff01;形如&#xff1a;token":&q…

Python入门【​编辑、组合、设计模式_工厂模式实现 、设计模式_单例模式实现、工厂和单例模式结合、异常是什么?异常的解决思路 】(十七)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小王&#xff0c;CSDN博客博主,Python小白 &#x1f4d5;系列专栏&#xff1a;python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 &#x1f4e7;如果文章知识点有错误…

matlab使用教程(10)—脚本和函数

1.概述 MATLAB 提供了一个强大的编程语言和交互式计算环境。您可以使用此语言在 MATLAB 命令行中一次输入一个命令&#xff0c;也可以向某个文件写入一系列命令&#xff0c;按照执行任何 MATLAB 函数的相同方式来执行这些命令。使用 MATLAB 编辑器或任何其他文件编辑器可以创建…

使用HTTP隧道时如何应对目标网站的反爬虫监测?

在进行网络抓取时&#xff0c;我们常常会遇到目标网站对反爬虫的监测和封禁。为了规避这些风险&#xff0c;使用代理IP成为一种常见的方法。然而&#xff0c;如何应对目标网站的反爬虫监测&#xff0c;既能保证数据的稳定性&#xff0c;又能确保抓取过程的安全性呢&#xff1f;…

Gartner发布《2023年全球RPA魔力象限》:90%RPA厂商,将提供生成式AI自动化

8月3日&#xff0c;全球著名咨询调查机构Gartner发布了《2023年全球RPA魔力象限》&#xff0c;通过产品能力、技术创新、市场影响力等维度&#xff0c;对全球16家卓越RPA厂商进行了深度评估。 弘玑Cyclone&#xff08;Cyclone Robotics&#xff09;、来也&#xff08;Laiye&am…

Visual Studio Code中对打开的脚本格式统一

什么是Language Server Protocol (LSP)? Language Server Protocol&#xff08;语言服务器协议&#xff0c;简称LSP&#xff09;是微软在2016年提出的一套统一的通讯协议方案。LSP定义了一套编辑器或者IDE与语言服务器&#xff08;Language Server&#xff09;之间使用的协议&…

【笔记】移动光猫改桥接

1. 登录后台 移动光猫的超管和密码&#xff08;百度的&#xff09; 账号&#xff1a;CMCCAdmin 密码&#xff1a;aDm8H%MdA 浏览器访问 192.168.1.1 并登录 2. 选择连接 点击“网络”&#xff0c;在“连接名称”下拉框选择 INTENET_R_VID 字样的连接&#xff0c;并截图备…

构建Docker容器监控系统(Cadvisor +InfluxDB+Grafana)

目录 案例概述 Cadvisor InfluxDBGrafana 1.1、 Cadvisor 1.2、InfluxDB 1.3、Grafana 1.4、监控组件架构 1.5、开始部署 安装docker-ce 阿里云镜像加速器 创建自定义网络 创建influxdb容器 案例概述 Docker作为目前十分出色的容器管理技术&#xff0c;得到大量企业…

CTF流量题解http1.pcapng

使用Wireshark工具打开流量文件http1.pcapng&#xff0c;如下图所示。 在过滤检索栏输入http&#xff0c;wireshark自动进行过滤。

2023牛客暑期多校训练营6 A-Tree (kruskal重构树))

文章目录 题目大意题解参考代码 题目大意 ( 0 ≤ a i ≤ 1 ) , ( 1 ≤ c o s t i ≤ 1 0 9 ) (0\leq a_i\leq 1),(1 \leq cost_i\leq 10^9) (0≤ai​≤1),(1≤costi​≤109) 题解 提供一种新的算法&#xff0c;kruskal重构树。 该算法重新构树&#xff0c;按边权排序每一条边…