• 面试题整理:vue 的双向数据绑定的实现原理?


    vue 双向数据绑定实现在的原理?

    vue 实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。

    当所一个普通Javascript 对象传给 Vue 实例来作为它的data 选项时,Vue 将遍历它的属性,用Object.defineProperty() 将它们转为 getter/setter。用户看不到getter/setter,但是在内部它们让Vue追踪依赖,在属性被访问和修改时通知变化。

    Vue 的数据双向绑定 将 MVVM 作为数据绑定的入口,整合 Observer,Compile和Watcher三者,通过Observer 来监听自己的 model 的数据变化,通过 Compile 来解析编译模板指令(vue 中是用来解析{{}}),最终利用watcher 搭起Observer 种Compile之间的通信桥梁,达到数据变化-->视力图更新;视图交互变化(input)-->数据 model 变更双向绑定效果。

    Object.defineProperty()

    Object.defineProperty()方法用于在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。注意:只能在Object构造器对象上调用此方法,而不能在任意一个Object类型的实例上调用。

    Object.defineProperty(obj,prop,descriptor)

    参数

    obj:目标对象,就是要在这个对象上面定义属性

    prop:要定义或修改的属性的名称或Symbol。

    descriptor:要定义或修改的属性描述符。是一个对象通过赋值操作添加的普通属性是可枚举的,(for...in 或 Object.keys 方法),即可以改变这些属性的值,也可以删除这些属性。Object.defineProperty()方法可以通过对属性的配置,实现更精确的控制

    关于descriptor:对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。

    数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。

    存取描述符是由getter函数和setter 函数所描述的属性。

    一个描述符只能是这两者其中之一;不能同时是两者。

    数据描述符和存取描述符都是对象。它们共享以下可选键值(默认值是指在使用Object.defineProperty()定义属性时的默认值):configurable 是否可以删除目标属性:当且仅当该属性的configurable 键值为 true 时,该属性的描述符才能够被改变,同时改属性也能从对应的对象上被删除。(使用delete删除) 默认为 false。

    enumberable 

    当且仅当该属性的enumerable键值为 true时,该属性才会出现在对象的枚举属性中。默认为 false.


    value 该属性对应的值。可以是任何有效的JavaScript值(数值,对象,函数)。

    默认为undefined。

    writable 该属性的值是否可以被重写:当且仅当该属性的 writable 键值为 true时,属性的值,也就是上面的value,才能被赋值运算符改变。默认为false。

    存取描述符还具有以下可选键值,get 属性,是一个函数,是一种获得属性值的方法

    如果没有getter,则为undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入this对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。默认为undefined。

    set 属性,是一个函数,是一种设置属性值的方法

    如果没有setter,则为undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的this 对象。默认为undefined。

    示例:

    1. <script>
    2. // 在对象中添加一个设置了存取描述符属性的示例
    3. var bValue = 38;
    4. Object.defineProperty(o, "b", {
    5. // 使用了方法名称缩写(ES2015 特性)
    6. // 下面两个缩写等价于:
    7. // get : function() { return bValue; },
    8. // set : function(newValue) { bValue = newValue; },
    9. get() {
    10. console.log('有人访问数据了');
    11. return bValue;
    12. },
    13. set(newValue) {
    14. console.log('设置了新值');
    15. bValue = newValue;
    16. },
    17. enumerable: true,
    18. configurable: true
    19. });
    20. o.b; // 38
    21. // 对象 o 拥有了属性 b,值为 38
    22. // 现在,除非重新定义 o.b,o.b 的值总是与 bValue 相同
    23. // 数据描述符和存取描述符不能混合使用
    24. Object.defineProperty(o, "conflict", {
    25. value: 0x9f91102,
    26. get() { return 0xdeadbeef; }
    27. });
    28. // 抛出错误 TypeError: value appears only in data descriptors, get appears only in accessor descriptors
    29. </script>

    说明:拥有布尔值的键 configurable、enumerable 和 writable 的默认值都是 false。

    属性值和函数的键value、get和set 字段的默认值为undefined。

    实现vue的双向数据绑定:

    1. <div id='app'>
    2. </div>
    3. <script>
    4. //模仿 Vue操作dom 的语法
    5. //我们自己创建一个Vue 函数
    6. const Vue =function({el,data={message:''}}){
    7. //绑定getset 方法
    8. Object.defineProperty(this,'message',{
    9. get:()=>{
    10. return document.getElementById(el).innerHTML
    11. },
    12. set:()=>{
    13. document.getElementById(el).innerHTML=val
    14. }
    15. })
    16. }
    17. const v=new Vue({
    18. el:'app',
    19. data:{
    20. message:'hello'
    21. }
    22. })
    23. v.message //返回hello
    24. v.message='HI' //将div 内的内容变为 HI
    25. </script>

  • 相关阅读:
    springboot统一异常处理(返回json)并支持所有异常格式化返回
    Linux系统编程(七):线程同步
    创作纪念日-我的第1024天
    Archery- SQL审核查询平台告警通知设置
    读完 RocketMQ 源码,我学会了如何优雅的创建线程
    Nano 编辑器中,怎样保存和退出
    【Git】Git 学习笔记_操作远程仓库
    说说验证码功能的实现
    smartgit的摘取功能(cherry-pick )介绍
    无代码开发批量打印入门教程
  • 原文地址:https://blog.csdn.net/qq_42417923/article/details/126701388