Vue数据监听Object.definedProperty()方法的实现

简介: Vue数据监听Object.definedProperty()方法的实现

Object.definedProperty()

1. 基本方法

    let book = {};
    Object.definedProperty(book, 'name', {
      value: 'John',
      writable: false,
      configurable: false,
      enumerable: false,
      get() {
        return newValue;
      },
      set(newValue) {
        book.name = newValue;
      },
    });

    2. 属性作用

    value:为当前设定的对象book的属性name的值,此处也可以设定默认值。
    如果不设定默认为
    undefined

    writable:能否修改对象book的属性name的值。

    true: 代表当前的值可通过赋值的方式(见下文)属性重定义的方式(见下文)的方式可进行修改

    false: 和 true 的情况相反,也就是不能修改对象的属性的值

    configurable:表示当前对象的属性能否被删除。

    true: 可以删除对象的属性

    false: 不能删除对象的属性

    enumerable: 定义道德对象的属性是否可以在 for...in 循环和 Object.keys() 中进行遍历。

    (1) value 属性


    let person = {};
    //  赋值的方式
    person.name = 'rose';
    //  属性重定义的方式
    Object.defineProperty(person, 'name', {
               value: 'jack',
    });

    (2) writable 属性


    // 情况一:writable: false
    let person = {};
    Object.defineProperty(person, 'name', {
      value: 'jack',
      writable: false,
    });
    person.name = 'rose';
    console.log('赋值方式person.name', person.name); //  jack
    Object.defineProperty(person, 'name', {
      value: 'jack',
      writable: false,
    });
    console.log('属性重定义方式person.name', person.name); //  jack
    // 情况二:writable: true
    let person = {};
    Object.defineProperty(person, 'name', {
      value: 'jack',
      writable: true,
    });
    person.name = 'rose';
    console.log('赋值方式person.name', person.name); //  rose
    Object.defineProperty(person, 'name', {
      value: 'john',
    });
    console.log('属性重定义方式person.name', person.name); //  john

    (3)configurable 属性


    // 情况一:configurable: false
    let person = {};
    Object.defineProperty(person, 'name', {
      value: 'jack',
      configurable: false,
    });
    delete person.name;
    console.log('🚀person', person); // person {name: jack}
    // 情况二:configurable: true
    let person = {};
    Object.defineProperty(person, 'name', {
      value: 'jack',
      configurable: true,
    });
    delete person.name;
    console.log('🚀person', person); // person {}

    (4) enumerable 属性


    let person = {};
    Object.defineProperty(person, 'name', {
      value: 'jack',
      enumerable: true,
    });
    person.gender = 'man';
    Object.defineProperty(person, 'age', {
      value: '26',
      enumerable: false,
    });
    console.log(Object.keys(person)); // [0:'name',1:'gender']
    for (const key in person) {
      console.log(key);
    } // name gender

    (5) get()方法

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

    (6) set() 方法

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

    3. 原理实现

    在 MVVM 框架中,一是监听数据的变化,二是数据驱动。

    在通常使用中我们使用 Object.definedProperty() 来实现监听数据的变化,或者使用 Proxy 和 反射。

    本章通过使用 MutationObserver 来实现 Object.definedProperty() 对数据变化的监听。

    (1) API 的使用

    定义:MutationObserver 构造函数对 DOM 树所做的更改提供了监听的能力。替代了旧的 MutaionEvents
    功能。

    返回值:MutationObserver 创建后并返回一个 new MutationObserver,当 DOM 发生改变时,会调用
    制定的回调函数。

    注意点:

    MutationObserver API 是异步触发的,DOM 的改变并不会马上触发,而是等到所有对 DOM 改变的操作
    完成后,整体的触发一次。

    面对多次的 DOM 修改,MutationObserver 会将多次的改变记录封装成一个数组进行处理,而不是一条
    一条进行处理。

    MutationObserver 在不影响浏览器性能的情况下响应 DOM 的更改。

    基本方法:

    disconnect():停止 MutationObserver 的监听,直到再次 observe() 再次被调用。

    observe():开始监听,并通过回调函数让 MutationObserver 接受通知。

    takeRecords():从 MutationObserver 的通知队列中移除所有挂起的通知,并在一个新Array
    MutationObserver 对象中返回它们。

    (2) 代码实现


    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Object.definedProperty的实现</title>
      </head>
      <body>
        <div id="app">
          <h1 id="h"></h1>
        </div>
      </body>
    </html>
    <script>
      // 选择要观察的节点
      const targetNode = document.getElementById('app');
      // 具体要观察节点那些改变
      const config = { attributes: true, childList: true, subtree: true };
      // 创建一个回调函数的实例,节点发生改变时执行的回调函数
      const Observer = new MutationObserver((mutationList, observer) => {
        mutationList.forEach((item, index) => {
          if (item.type === 'childList') {
            console.log('有节点发生改变,当前节点的内容是:', item.target.innerHTML);
          } else if (item.type === 'attributes') {
            console.log('修改了' + item.attributeName + '属性');
          }
        });
      });
      // 开始观察节点是否发生变化
      Observer.observe(targetNode, config);
      // 停止观察
      // observer.disconnect();
    </script>


    (3) 输出结果

    相关文章
    |
    22天前
    |
    缓存 JavaScript UED
    Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
    在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
    126 64
    |
    28天前
    |
    监控 JavaScript 算法
    深度剖析 Vue.js 响应式原理:从数据劫持到视图更新的全流程详解
    本文深入解析Vue.js的响应式机制,从数据劫持到视图更新的全过程,详细讲解了其实现原理和运作流程。
    |
    1月前
    |
    JavaScript 前端开发
    `Object.create()` 方法的参数
    【10月更文挑战第29天】`Object.create()` 方法的参数提供了多种创建对象和控制对象属性及继承关系的方式,开发人员可以根据具体的需求灵活运用,以实现更高效、更符合设计要求的对象创建和继承机制。
    |
    1月前
    |
    存储 Java 程序员
    Java基础的灵魂——Object类方法详解(社招面试不踩坑)
    本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
    114 4
    |
    1月前
    |
    设计模式
    在实际开发中,什么时候应该使用 `new` 关键字,什么时候应该使用 `Object.create()` 方法?
    【10月更文挑战第29天】`new` 关键字适用于创建具有特定类型和初始化逻辑的对象实例,以及实现基于原型链的继承;而 `Object.create()` 方法则适用于基于现有对象创建相似对象、避免构造函数的副作用、创建具有特定原型链的对象等场景。在实际开发中,需要根据具体的需求和设计模式来选择合适的方法来创建对象,以实现更高效、更灵活的代码结构。
    |
    1月前
    |
    JavaScript 数据管理 Java
    在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
    【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
    59 1
    |
    1月前
    |
    JavaScript 开发者
    在 Vue 3 中使用 Proxy 实现数据的双向绑定
    【10月更文挑战第23天】Vue 3利用 `Proxy` 实现了数据的双向绑定,无论是使用内置的指令如 `v-model`,还是通过自定义事件或自定义指令,都能够方便地实现数据与视图之间的双向交互,满足不同场景下的开发需求。
    62 1
    |
    2月前
    |
    API
    vue3知识点:响应式数据的判断
    vue3知识点:响应式数据的判断
    30 3
    |
    2月前
    |
    存储 缓存 JavaScript
    vue表单案例练习:vue表单创建一行数据及删除数据的实现与理解
    vue表单案例练习:vue表单创建一行数据及删除数据的实现与理解
    49 2
    |
    2月前
    |
    JavaScript
    Vue 的响应式原理中 Object.defineProperty 有什么缺陷
    Vue 的响应式原理主要依赖于 `Object.defineProperty`,但该方法存在一些缺陷:无法检测到对象属性的添加和删除,且对大量数据进行代理时性能较差。Vue 3 中改用了 Proxy 来解决这些问题。