vue源码之数据侦测

VUE源码解析——Object、Array变化侦测原理解析,学习Vue中如何实现数据的响应式系统,从而达到数据驱动视图。 VUE源码解析——Object变化侦测原理解析一、什么是变化侦测?二、Object变化侦测1.Object.defineProperty方法2.依赖收集什么是依赖收集何时收集依赖?何时通知依赖更新?依赖管理器Dep类Watcher类不足之处Object变化侦测流程总结 ├─dist # 项目构建后的文件 ├─scripts # 与项目构建相关的脚本和配置文件 ├─flow # flow的类型声明文件 ├─s 阅读详情

数据侦测

思路:先侦测对象的一个属性,再侦测对象的全部属性,再递归侦测子属性

在来解决数组的侦测问题

最后收集依赖

侦测一个属性

vue2中使用使用Object.defineProperty来监测对象的一个属性,

Object的变化侦测

1. 什么是变化侦测

我们在写vue组件的时候,在模板里面使用的变量,当该变量的值改变的时候,能够直接渲染在页面上,这是数据的响应式原理,如何实现这个功能呢?这其实涉及到很多原理和算法,就包括变化侦测,通过变化侦测,我们就可以侦听到该变量的变化,在这个基础上再实现其他的功能

举个例子:

let obj = {
    a: 1,
    b: 2,
    c: {
        m: {
            n: 4
        }
    }
}

当对象obj被侦测了的时候,当obj.a发生变化的时候,我们就可以侦测的到,即能够侦测到obJ的全部属性,不仅如此,如果obj的属性值是一个对象,我们也要能够侦测的到,即能够侦测的到obj.c.m.n

2. 如何实现对象的变化侦测

思路

对一个需要被侦听的对象,先遍历它的所有属性,并用Obj.defineProperty来侦听每一个属性,然后再判断每个属性值是否是一个对象,如果是的话还需要遍历这个对象的所有属性

具体实现
observe
  • 首先需要有Observe这个函数,它算是变化侦测的一个入口,将需要被侦测的对象传给这个函数

    比如:

    let obj = {
        a: 1,
        b: 2,
        c: {
            m: {
                n: 4
            }
        }
    }
    
    Observe(obj)  // 此时Obj即被侦测了!
    
  • 需要判断定的参数值是否是对象或者该对象是否已经被侦测了,当该对象具有__ob__时,即表示已经被监测了

  • 若没有__ob__这个属性时,即没有被侦测,此时需要用到Observer这个对象(注意后面有“r),在这个对象上对这个对象进行监测

  • 具体实现代码

    export default function (value) {
        // 如果value不是对象,什么都不做
        if (typeof value != 'object') return;
        // 定义ob
        var ob;
        if (typeof value.__ob__ !== 'undefined') {
            ob = value.__ob__;
        } else {
            ob = new Observer(value);
        }
        return ob;
    }
    
    
Observer类

上文提到的,Observer类是要监听该对象的所有属性,具体功能如下:

  • Observer接受一个要侦听的对象,先给这个对象添加一个__ob__属性,属性值为此次Observer实例,表示这个对象的所有属性都已经被监听了,并让这个__ob__不能被枚举

  • 定义一个方法walk,利用这个方法遍历对象的属性,使用defineReactive这个函数监听所有属性

  • 实现代码:

    class Observer {
        // value就是被侦听的对象
        constructor(value) {
            // 利用这个属性给这个对象添加__ob__属性,函数在下面
            def(value, '__ob__', this, false)
            // 监听每个属性
            this.walk(value)
        }
        
        walk(value) {
            // 遍历属性,通过这个方法侦听每个属性
            for(let k in value) {
                defineReactive(value, k)
            }
        }
    }
    
    const def = function (obj, key, value, enumerable) {
        Object.defineProperty(obj, key, {
            value,
            enumerable,
            writable: true,
            configurable: true
        });
    };
    
defineReactive

利用这个函数,通过defineProperty对传进来的属性进行监听,并判断属性值是否是对象,是的话再调用observe这个函数监听该对象,类似于递归调用,但不是递归本身,而是observe、Observer、defineReactive三者循环调用。具体功能如下:

  • 接三个参数,data是对象,key是属性,value是属性值,默认等于data[key]

  • 调用Object.defineProperty监听每个属性,并配置get,set方法,在get中返回value,set中修改value,注意此时的value是传进来的参数,但js会分配给这个参数单独的内存空间,所以每调用一次,参数的地址都是不一样的。

  • 利用observe,将value传进去,value是对象属性的值,这一步是处理属性值是对象的情况,但在这个函数中不用判断value是否是对象,因为在observe中已经有判断若传进来的不是对象,直接return了

  • 另外,当属性被设置了新的值(newValue)的时候,此时会触发set方法,需要判断新的值是否是对象,即调用observe(newValue)

  • 具体代码:

    function defineReactive(data, key, value = data[key]) {
        Object.defineProperty(data, key, {
            // 可枚举
            enumerable: true,
            // 可以被配置,比如可以被delete
            configurable: true,
            get() {
                return value
            },
            set(newValue) {
                // newValue就是想要设置的新值
                // 即此时没有改变属性值
                 if (val === newValue) {
                    return;
                }
                value = newValue
                // 判断新值是否是对象
                observe(newValue)
            }
        })
       // 判断设置的值是否是对象 
        observe(value)
    }
    

依赖收集

现在我们已经将对象的变化侦测实现了,即对象属性值发生变化时我们能够侦测的到,之后呢,我们是不是就得去通知所以使用这些对象的函数或模板组件做出相应的改变,前提是我们得知道哪些使用了这些对象,我们把使用这些变化侦测对象的模板或组件等称为依赖

什么是依赖

依赖就是使用了这个数据的模板或者组件

举个例子:

<template>
    <div>
        {{name}}
    </div>
</template>

在上面的这个模板中,使用了name这个响应式变量,所以这个模板就是这个变量name的一个依赖。需要注意的是,我们不是直接收集这些模板的,而是收集一个叫做Watcher的对象实例,Watcher与真正模板的重新渲染不是这一章要了解的,我们这一章主要是收集Watcher实例

举个例子:

vm.$watch('a.b.c', callback)

在vue组件中,这段代码表示的是当data.a.b.c属性发生变化时,会触发callabck这个回调函数

那其实这里就是用到了这个data.a.b.c属性,相当于这个属性的一个依赖,我们用Watcher实例作为依赖的话,就相当于

new Watcher(data, 'a.b.c', callback)
如何收集依赖

当执行new Watcher(data, 'a.b.c', callback)时,会触发data.a.b.c的get操作,此时就可以把这个依赖通过get方法收集起来,如果修改了这个属性的话,就会触发set操作,此时就需要通知这些依赖。总的来说,就是在getter中收集依赖,在setter中触发(通知)依赖

具体实现
  • 首先,需要一个Dep类,这个类是用来管理每一个属性的依赖的,包括添加依赖,触发依赖等。所以需要在每个属性上new一个Dep实例
  • 还需要一个Watcher类,这个类就是依赖,每使用一个被侦测的对象的属性时,就会new一个Watcher实例,当被通知到属性值修改后,就会执行回调函数
Dep类
  • Dep类是用来管理属性的依赖的,所以每个属性必须拥有一个dep实例,在defineReactive这个函数中,我们会监听每个属性,所以在这里给属性加上一个dep实例最好不过了

  • dep类上有一个数组subs,用来添加每个属性的依赖

  • 有一个depend方法,在这个方法中,会判断是否有Dep.target这个对象,如果有的话,就表示此时有依赖需要添加,Dep.target就是一个我们自己指定的全局的位置,你用window.target也行,只要是全剧唯一,没有歧义就行,当我们new一个Watcher实例时,就会给Dep.target设置一个值,依赖添加完成之后,再把Dep.target设置为null

  • 还有一个notify方法,当侦听的属性发生变化时,会通知每一个依赖,出发每一个依赖的update方法

  • 具体代码:

    class Dep {
        constructor() {
            // 用数组存储自己的订阅者。subs是英语subscribes订阅者的意思。
            // 这个数组里面放的是Watcher的实例
            this.subs = []
        }
        depend() {
            if(Dep.target) {
                this.add(Dep.target)
            }
        }
        addSub(sub) {
            this.subs.push(sub)
        }
        notify() {
            const subs = this.subs.slice()
            for(let i = 0; i < subs.length; i++) {
                subs[i].update()
            }
        }
    }
    
Watcher类
  • Watcher实例就是依赖,接受三个参数,分别为target, expression, callback,target就是监听的对象,expression就是监听对象的某个属性,callback就是这个属性改变时会执行的函数

    new Watcher(data, 'a.b.c', callback)
    
  • 在这个类中,首先会解析a.b.c,得到所使用的属性,此时需要一个parsePath函数,该函数会返回一个函数(赋值在实例的getter上),并获得所使用的属性,但要注意的是,通过这个函数我们并不知道这个属性属于那个对象,只有通过我们传入一个对象后才知道

    function parsePath(str) {
        var segments = str.split('.')
        return (obj) => {
            for(let i = 0; i < segments.length; i++) {
                // 若obj不存在,则表示找不到这个属性
                if(!obj) return
                obj = obj[segments[i]]
            }      
            return obj  
        }
    }
    
  • 接着,会调用自身的get方法,意味着进入依赖收集阶段,会将全局的Dep.target设置为Watcher本身,并调用自身的getter方法,在这个方法中会触发属性的getter操作,并在此操作中将Watcher收集在dep上,收集结束后要记得将Dep.target设置为null

  • 最后,还需要有一个update方法,当属性值改变之后,能够通知到该依赖,并执行这个方法

  • 代码如下:

    var uid = 0;
    export default class Watcher {
        constructor(target, expression, callback) {
            console.log('我是Watcher类的构造器');
            this.id = uid++;
            this.target = target;
            // parsePath(expression)返回一个函数,放在getter上,所以getter没有什么特别含义
            this.getter = parsePath(expression);
            this.callback = callback;
            this.value = this.get();
        }
        update() {
            this.run();
        }
        get() {
            // 进入依赖收集阶段。让全局的Dep.target设置为Watcher本身,那么就是进入依赖收集阶段
            Dep.target = this;
            const obj = this.target;
            var value;
    
            // 只要能找,就一直找
            try {
                // 此时要找到obj里expression这个属性值 
                value = this.getter(obj);
            } finally {zhih1
                Dep.target = null;
            }
    
            return value;
        }
        run() {
            this.getAndInvoke(this.callback);
        }
        getAndInvoke(cb) {
            const value = this.get();
    
            if (value !== this.value || typeof value == 'object') {
                const oldValue = this.value;
                this.value = value;
                cb.call(this.target, value, oldValue);
            }
        }
    };
    

数组的变化侦测

var obj = {
    a: {
        m: {
            n: 5
        }
    },
    b: 10,
    c: {
        d: {
            e: {
                f: 6666
            }
        }
    },
    g: [22, 33, 44, 55]
};

像上面这段代码中,对象的属性g是数组的情况下,我们对数组进行push等操作时,这个动作是不会被拦截的,所以通过getter/setter的方式行不通

如何追踪变化

前面Object的变化时靠getter来追踪的,一个属性发生变化,就会触发getter。同理,我们只要能在数组中使用push等操作时被通知,就能实现同样的功能

但在es6之前,js没有提供可以拦截原型方法的能力,所以我们只能用自定义的方法去覆盖原型上的方法。

经过整理,我们发现Array原型上有7个方法可以改变数组自身内容,分别为:push, pop, shift, unshift, split, sort, reverse,所以,我们可以用一个拦截器,每当数组使用这些方法的时候,其实执行的是拦截器里的自定义的方法,如图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sdS9oKpH-1649087186200)(变化侦测.assets/image-20220330164500023.png)]

拦截器设计

  • 我们要让数组的原型指向拦截器上,并在拦截器上定义push这些方法,再让拦截器指向Array.prototype,这样数组还能使用Array的其他方法

  • 拦截器其实就是一个对象,在这个对象上添加push这些方法,并用Object.defineProperty()监听这些属性

  • 为了保证原来的push等功能不被剥掉,我们需要备份原方法,添加在拦截器的属性上

  • 有三种方法push\unshift\splice能够插入新的内容(有可能是对象),所以需要再observe一下这些新元素

  • 定义一个函数array.js来设计拦截器,并把拦截器暴露出去

    具体代码如下:

    const arrayPrototype = Array.prototype
    
    // 将拦截器原型指向数组原型上
    export const arrayMethods = Object.create(arrayPrototype)
    
    // 要被改写的7个数组方法
    const methodsNeedChange = [
        'push',
        'pop',
        'shift',
        'unshift',
        'splice',
        'sort',
        'reverse'
    ];
    
    methodsNeedChange.forEach((methodName) => {
        // 保留原先的方法
        const original = arrayPrototype[methodName]
        // 给拦截器定义方法,def函数上文有介绍过
        def(arrayMethods, methodName, function() {
            // 恢复原来的方法,注意这里this指向数组自身,不能用箭头函数
          	original.apply(this, arguments)
              // 把类数组对象变为数组
            const args = [...arguments];
            // 把数组身上的__ob__属性取出来,要记得数组是一个对象,会在observer的时候添加__ob__属
            // 性,并且该属性值是observer实例
            const ob = this.__ob__
            // 有三种方法push\unshift\splice能够插入新项,现在要把插入的新项也要变为observe的
            let inserted = [];
    		 switch (methodName) {
                case 'push':
                case 'unshift':
                    inserted = args;
                    break;
                case 'splice':
                    // splice格式是splice(下标, 数量, 插入的新项)
                    inserted = args.slice(2);
                    break;
            }
             // 判断有没有要插入的新项,让新项也变为响应的,ob.observeArray下文会介绍
            if (inserted) {
                ob.observeArray(inserted);
            }
            // 触发时表示数组被更改,需要通知依赖,这里要注意的是!!!比如执行obj.g.push()时,是要通知		// obj的,obj身上也有一个dep
            ob.dep.notify();
        }, false)
    })
    

使用拦截器覆盖Array原型并挂载在数组上

  • 由于对象和数组的监测方式是不同的,所以在new一个observer实例的时候需要判断传入的value是否是一个数组

  • 如果是一个数组的话,就需要将原型添加到拦截器上

  • 若数组内可存在对象的话,也是需要被监测的,所以需要observe每一个数组元素,但不能像对象一样使用walk()方法,即此时数组内的某个普通元素变化时不能检测到?????????????????

  • 具体代码在observer这个类中:

    class Observer {
        constructor(value) {
            // 每一个Observer的实例身上,都有一个dep
            this.dep = new Dep();  // 给数组,对象收集依赖
            // 给实例(this,一定要注意,构造函数中的this不是表示类本身,而是表示实例)添加了__ob__属性,值是这次new的实例
            def(value, '__ob__', this, false);
            // console.log('我是Observer构造器', value);
            // 不要忘记初心,Observer类的目的是:将一个正常的object转换为每个层级的属性都是响应式(可以被侦测的)的object
            // 检查它是数组还是对象
            if (Array.isArray(value)) {
                // 如果是数组,要非常强行的蛮干:将这个数组的原型,指向arrayMethods
                // es6写法  Object.setPrototypeOf(value, arrayMethods);
                value.__proto__ = arrayMethods
                // 让这个数组变的observe
                this.observeArray(value);
            } else {
                this.walk(value);
            }
        }
        // 遍历
        walk(value) {
            for (let k in value) {
                defineReactive(value, k);
            }
        }
        // 数组的特殊遍历
        observeArray(arr) {
            for (let i = 0, l = arr.length; i < l; i++) {
                // 逐项进行observe
                observe(arr[i]);
            }
        }
    };
    
数组不支持_proto_的情况

当不能使用__proto__的时候,Vue的做法是直接将拦截器上的方法直接设置在被侦测的数组上

function protoAugment(target, src, key) {
    target.__proto__ = src
}

function copyAugument(target, src, keys) {
    for(let i = 0; i < keys.length; i++) {
        const key = keys[i]
        def(target, key, src[key])
    }
}

// Observer类部分
const hasProto = '__proto__' in {}
const arrayKeys = Object.getOwnPropertyNames(arrayMethods)
if(Array.isArray(value)) {
    const augument = hasProto ? protoAugment : copyAugument
    augument(value, arryMethods, arrayKeys)
} else {
    this.walk(value)
}
约2万字-Vue源码解读汇总篇(续更) 未完待续...Vue源码解读:06Vue3探索篇Vue源码解读:05生命周期篇Vue源码解读:04模板编译篇Vue源码解读:03虚拟Dom篇Vue源码解读:02变化侦测篇Vue源码解读:01核心思想篇Vue源码解读:前言篇从写下的代码,到用户见到界面,大致经历以下几个流程:模板字符串=》ast树=》render函数=》vnode=》用户见到的界面。将开发者写下的模板字符串,经过一些列处理,生成render函数的这一过程就是模板编译。简单地说,模板编译解析就是为了得到render函数。 阅读详情

相关推荐

第三章、变化侦测相关的API实现原理

本章我们来讲解关于变化侦测的三个API:vm.watch、vm.watch、vm.watch、vm.set、vm.$delete 1、vm.$watch 语法:vm.$watch(expOrFn, callback, [options]) 使用: vm.$watch('a.b.c',(newVal,oldVal)=>{ // do something }); 或者 var unwa...

Bidding 388

vue 源码中依赖 Watcher 和 parsePath函数

vue依赖watcher和parsePath函数

qq_42744920的博客 514

WGCNA样本量不够怎么办?5种替代方案帮你解决小样本基因共表达分析难题

本文针对WGCNA样本量不足的问题,提供了5种科学替代方案,包括CEMiTool、参数调整、多组学数据整合、机器学习特征提取和公共数据利用。这些方法帮助研究者在小样本条件下仍能进行可靠的基因共表达分析,特别适用于罕见病和珍贵临床样本研究。

weixin_42554042的博客 304

Vue2 响应式原理

可以看到,通过该方法,我们可以更加精细地控制对象属性的可读性、可写性、可枚举性和可配置性等特性,并且可以为一个属性自定义读取器(get)和写入器(set)等逻辑处理。简单来说,在 Vue2 响应式系统中,当数据发生改变时,会触发 get 和 set 方法,get 方法会收集所有依赖该数据的 Watcher 对象,set 方法会通知 Dep 对象触发所有 Watcher 对象的回调函数进行更新。当其中任意一个属性的值发生变化时,其对应的依赖都会被更新,从而触发其绑定的观察者的回调函数。

weixin_62992614的博客 3081

保姆级教程:用SNAP处理哨兵一号数据,5步搞定城区范围提取(附江西晋城案例)

本文提供了一份详细的保姆级教程,介绍如何使用SNAP软件处理哨兵一号数据,通过5个关键步骤快速提取城区范围。以江西晋城为例,教程涵盖数据准备、预处理、核心处理流程、自动化搭建及成果分析,帮助用户轻松掌握SNAP操作技巧,适用于城市规划、环境监测等领域。

weixin_32535389的博客 454

OpenGL计算着色器工作组设置测试

先看看不同的显卡上工作组的数量情况。 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, data); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, data + 1); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, data...

qq_26328385的博客 1484

Vue响应式原理:Watcher与Dep的深度解析

本文通过一个交互式示例深入解析了Vue响应式系统中Watcher与Dep的核心机制。文章展示了:1)Dep作为依赖收集器,负责管理每个响应式属性的Watcher订阅;2)Watcher作为观察者,在数据访问时被收集,在数据变更时执行回调更新视图。通过可视化演示了"数据劫持-依赖收集-触发更新-执行回调"的工作流程,并提供了简化版的Dep和Watcher实现代码,帮助理解Vue如何实现数据与视图的自动同步。

油墨香^-^的博客 721

GD32F4x芯片加密实战:从读保护到安全启动全解析

本文详细解析了GD32F4x芯片加密的实战操作,从读保护功能到安全启动全流程。通过具体代码示例和应用场景分析,帮助开发者有效防止固件被盗用,提升工业控制、智能门锁等场景下的数据安全性。重点介绍了读保护功能的底层机制、配置步骤及常见问题解决方案。

weixin_42629671的博客 207

《深入浅出vue.js》中变化侦测的源码以及解析

《深入浅出vue.js》中变化侦测的源码以及解析 背景 最近由于公司知识体系变动,需要学习vue来适应新的开发平台,我选择了《深入浅出vue.js》来进行学习,之前有了解过一些vue知识,这次打算深入学习一下,尤其是第一篇变化侦测,学习过程中对javascript也增加了不少理解,我把代码都手打了出来,代码中有很多按照自己理解打上的注释,这里分享给大家。 开门见山 这里我不给大家解释他是什么,书中...

Run_youngman的博客 519

Juniper SRX PPPoE配置

set interfaces pp0 unit 1 ppp-options chap default-chap-secret 拨号用户名密码。set interfaces pp0 unit 0 ppp-options chap default-chap-secret 拨号密码。set interfaces pp0 unit 0 ppp-options chap local-name 拨号用户名。6号口接运营商进行拨号。

Jian Sun_的博客 750

手把手教你学simulink(42.1)--储能系统场景示例:基于Simulink的电池+超级电容器混合储能系统

混合储能系统(HESS)结合了电池和超级电容器的优点,能够在满足高功率需求的同时提供较长的持续放电时间。这种组合特别适合用于电动汽车、可再生能源发电系统、电网频率调节等应用场景。本项目将详细介绍如何在MATLAB/Simulink中搭建一个完整的基于电池和超级电容器的混合储能系统,并提供具体的代码实现和设计步骤。如果你需要实现更复杂的控制逻辑,可以使用MATLAB Function模块。以下是一个简单的例子,展示了如何在该模块中实现一个条件逻辑,以分配电池和超级电容器的充放电任务。Matlab。

MHD0815的博客 543

Vue2(四):Vue监测数据的原理

如果我要点击按钮实现更新冯万宁儿的信息,那么如果一个属性一个属性地改,可以修改成功,并且Vue也会检测到并更新到页面。但是我如果直接把整个对象改了,可以修改成功,但是Vue监测不到并且不更新到页面,这是为啥捏?请君慢慢往下阅读 2.原生js模拟Vue监视data对象中的数据 用原生js写一个Vue监视data数据改变的效果 代码自己琢磨琢磨,有点儿意思。可以看出,Vue监视数据的原理,就是靠 如果不理解,想想前边讲Object.defineProperty时那个number 这只是个模拟,实际上Vue做了更

weixin_42044763的博客 2840

OpenClaw插件配置错误修复完全指南

插件文件名是插件目录结构正确package.json配置正确OpenClaw的插件系统还在快速迭代,偶尔会遇到这种配置问题。看错误信息检查配置文件检查实际文件对比差异修复问题大部分问题都能解决。查看官方文档:https://openclaw.ai/docs提Issue:https://github.com/openclaw/openclaw/issues加入Discord社区求助快速修复命令汇总。

Maynor的博客 4096

vue源码解析1 之数据响应之谜(数据侦测)

我与vue源码 之前写过一篇死磕vue源码,写了一篇就真心写不下去,vue的代码现在健壮的不要不要的那么写会越写越乱,最后会搞到自己都看不懂的地步。我写文章也是东一榔头西一棒锤,今天就继续搞vue的源码,不过这次的策略不一样的。我呢,分析了一下vue的几件神器: 数据响应式(也就是数据侦测); AST抽象语法树(个人理解就是虚拟DOM, 把字符串的DOM模版转换为对象形式的DOM树); diff算法(最小量更新); 当然了个人理解,vue就是以这几件大神器为底,建造起了一个前端框架。 数据侦测 每个框架

weixin_43139949的博客 365

YOLO26改进策略【卷积层】| CVPR 2024 可变形卷积 v4(DCNv4)无界权重提表达 + 线程合并降冗余,强化模型收敛速度

DCNv4(Deformable Convolution v4)是一种专为广泛视觉应用设计的高效算子,它对DCNv3进行了关键改进,有效解决了DCNv3存在的速度慢和表达能力受限等问题。

Limiiiing的博客 694

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

vue.3.0 dom赋值_Vue 3.0 源码分析数据侦测

2020年前端大事件之一,Vue 3.0终于正式发布了。作为一个大的版本更新,Vue 3 与 Vue 2相比,实现原理,使用方式等均有着不小的改动。本文主要会介绍讲述二块内容,分别是Vue 3.0 的简要介绍,Vue 3.0 数据侦测源码分析。小伙伴们可以根据自己的需求,查看对应的内容,也欢迎各位一起探讨,一起学习。Vue 3.0 简要介绍Vue 3 的 “前世今生”2016年,Vue ...

weixin_42301367的博客 369

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Vue源码数据侦测篇

Vue最大的特点就是数据驱动视图,动态变化,他由前一个状态到了后一个状态,页面也就应该变化,所以我们得到以下公式 UI = render(state) UI公式中:状态state是输入,页面UI输出,一旦状态发生改变,页面输出也就随之也改变,把这种特性称之为数据驱动视图。 把UI公式分为三个部分,state,render(),UI。 state和UI都是用户顶的,不变的是render(),所以Vue就扮演了render()角色,当Vue发生state变化之后,经过一系列加公,最后变化反映在UI上 Vue.

weixin_43405946的博客 210

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Vue源码系列讲解——变化侦测篇【上】(何为变化侦测)

最大的特点之一就是数据驱动视图,那么什么是数据驱动视图呢?在这里,我们可以把数据理解为状态,而视图就是用户可直观看到页面。数据驱动视图简单来说就是数据变化引起视图变化,那么第一步就是先要知道数据什么时候发生变化,也就是说对数据的变化要进行侦测。输出,状态输入一旦变化了,页面输出也随之而变化。变化侦测就是追踪状态,亦或者说是数据的变化,一旦发生了变化,就要去更新视图。其次,数据的变化侦测在三大框架中均有涉及,不同的框架有着自己的一套侦测机制。变化之后,经过一系列加工,最终将变化反应在。来实现变化侦测,而在。

小彭的博客 650

vue源码学习(数据侦测、虚拟DOM、Diff算法)

vue源码 ├─dist # 项目构建后的文件 ├─scripts # 与项目构建相关的脚本和配置文件 ├─flow # flow的类型声明文件 ├─src # 项目源代码 │ ├─complier # 与模板编译相关的代码 │ ├─core # 通用的、与运行平台无关的运行时代码 │ │ ├─observ

qq_43271330的博客 365

解析vue2.x源码之Object与Array的变化侦测

基本概念介绍: Vue框架是如何实现变量的变化侦测的呢? Object 利用了 Object.defineProperty 进行变量的getter与setter拦截,但数组的实现与 Object 有所不同,下面会从源码层面具体讨论这两种类型的变量如何实现变化侦测。 首先我们需要先了解Vue源码中的三个类: 一、Observer Observer类负责将复杂类型的变量转化成响应式数据,转化...

qq_36259513的博客 615

嗨,让我带你逐行剖析Vue.js源码(一个月时间github上star数已经破1600!!!)

短短一个月时间内本项目在github上star数量就已经破千!!!Hello,大家好,本人最近在github上做一个关于Vue源码的开源项目,项目内容是:利用工作之余时间逐行剖析Vuej...

frontend_frank的博客 948

vue源码简单剖析(1)---object如何实现变化侦测

vue最大的特点之一就是数据驱动视图,也就是数据的变化,引起视图的变化。那么,第一步肯定要知道数据什么时候发生变化,这就叫做对数据的变化侦测 想要知道数据什么时候发生变化,我们可以使用js的Object.defineProperty方法 let student = { 'age': 11, } 我们可以直接通过student.age读取到学生的年龄是11,但是当学生年龄的值被修改了,我们如何才能主动知道值被修改了呢? 我们可以使用Object.de...

mfuuty的博客 230

VUE源码解析

VUE源码理解 1.公式:UI=render(state) state是输入,UI是页面输出,VUE充当render()这个角色,当vue发现其state变化之后,经过一系列的加工,最终变化反映在UI上 Object的变化侦测 2.变化侦测 变化侦测是追踪状态,一旦数据发生变化,就会去更新视图 3.object的更新变化 let car = {} let val = 3000 Object.defineProperty(car, 'price', { enumerable: true, config

程文英 855

【深入浅出Vue.js篇】之变化侦测相关API实现原理

数据监听相关API实现原理

m0_48192059的博客 341

vue源码解析

vue源码解析 源码结构 ├─dist # 项目构建后的文件 ├─scripts # 与项目构建...

愚人码头的博客 69

Vue3 Beta版发布对于放弃 Object.defineProperty API你了解多少?(一)

千呼万唤使出来Vue3 Beta 版本终于在前几天发布了,为了更好的初始化性能在新版本中Vue把数据对象侦测的API 从Object.defineProperty 换成 Proxy,这么...

ItStar 458
上一篇: this指向问题全面解析
下一篇: leetcode15. 三数之和
Lin__hr
博客等级 码龄6年 5粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值