ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

3. 数组的响应式原理

2022-06-23 01:32:54  阅读:134  来源: 互联网

标签:__ arr 方法 响应 数组 push 原理 data


数组的响应式原理

一般使用数组很少使用 arr[1] = 100, arr.length = 10 这两种方式修改数组, vue2同样也不支持

vue2中实现数组响应式的方法是重写能改变数组的7个方法

特殊情况: 形如: arr: [1,2,3, {num: 100}], 这种数组里面有嵌套对象的, 也要能劫持对象的属性, 添加get和set

特殊情况2: arr: [1,2,3], arr.push({num: 20}), 在能改变数组的方法中, 如push一个对象, 那这个对象的属性也需要被劫持

上述为本章需要实现的目标

  1. 新建文件dist/2.array.html 文件, 内容如下

    <!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>array</title>
    </head>
    <body>
        <script src="vue.js"></script>
        <script>
            // 新建一个vue实例
            const vm = new Vue({
                data() {
                    return {
                       arr: [1,2,3, {num: 100}]
                    }
                }
            })
            // 一般使用数组很少使用 arr[1] = 100, arr.length = 10 这两种方式修改数组, vue2同样也不支持
            // vue2中实现数组响应式的方法是重写能改变数组的7个方法
            // 特殊情况: 形如: arr: [1,2,3, {num: 100}], 这种数组里面有嵌套对象的, 也要能劫持对象的属性, 添加get和set
            // 特殊情况2: arr: [1,2,3], arr.push({num: 20}), 在能改变数组的方法中, 如push一个对象, 那这个对象的属性也需要被劫持
            vm.arr.unshift({age: 3})
            console.log('vm.data', vm)
        </script>
    </body>
    </html>
    
    
    // 需要实现的目标:
    // 1. 重写数组方法
    // 2. 让数组中的对象也变成响应式
    
  2. 切入点, 接上一章, 在Observer类中值考虑了对象, 以及对象嵌套的情况,

    现在来处理数组, 修改Observer类如下

    // 新增一个if判断, 
    // 同目录新建array.js文件, 实现数组重写并引入
    // 新增observeArray方法, 对数组中的对象进行处理
    // 在data中添加一个不可枚举的属性 __ob__, 用来标识是否已经被劫持, 同时给observe方法里面新增一个判断逻辑, 同时给array.js里面提供observeArray方法
    
    class Observer {
        constructor(data) {
            // 2) 在data上增加一个属性__ob__, 指向this,便于在array.js里面使用Observer里面的observeArray方法
            // 同样这个属性可以作为一个标识, 表明属性是否有被劫持过, 可在observe方法中新增一个判断
            // 注意这个属性不可枚举, 不然会死循环
            Object.defineProperty(data, '__ob__', {
                value: this,
                enumerable: false
            })
            // 1) 针对对象和数组做区分
            if(Array.isArray(data)){
                // 数组需要实现两个内容: 
                // 1. 数组方法重写, 新建文件实现 array.js
                // 2. 遍历数组, 劫持其中的对象, 并称响应式
                data.__proto__ = newArrayProto
                this.observeArray(data)
            } else {
                // 对对象的属性劫持放在walk方法中
                this.walk(data)
            }
        }
    
        // 遍历对象, 给每一个属性添加响应式, defineReactive不在class中, 因为其他地方也可能用到, 写了外面
        walk(data) {
            Object.keys(data).forEach(key => defineReactive(data, key, data[key]))
        }
    
        // 循环数组, 找出其中的对象(这异步已经封装在observe方法里面, 不用做), observe每一项
        observeArray(data) {
            data.forEach(item => observe(item))
        }
    }
    
    
  3. 重写数组方法 在array.js文件中

    // 重写数组方法
    // 不能干掉旧的方法
    // 重新定义方法, 就是在执行push 方法的时候, 调用旧的push方法,注意this的指向问题,以及返回值 然后在添加一些自己的内容
    // 对新增的内容(肯定是数组)进行observeArray   ??? 注意进行observeArray是哪里来的
    
    
    // 先copy旧的数组
    let oldArrayProto = Array.prototype
    
    // 定义并导出新的原型
    export let newArrayProto = Object.create(oldArrayProto)
    
    // 能改变数组的7种方法
    let methods = ['push', 'pop', 'shift', 'unshift', 'reverse', 'sort', 'splice']
    
    methods.forEach(method => {
        newArrayProto[method] = function(...args) {
            const result = oldArrayProto[method].call(this, ...args)
    
            // 需要对新增的内容做处理, 新增的方法有 : push, unshift, 和 splice
            let inserted
            // 从实例上获取__ob__属性
            let ob = this.__ob__    
            switch(method) {
                case 'push':
                case   'unshift':
                    inserted = args
                    break
    
                case 'splice':
                    inserted = args.slice(2)
    
                default:
                    break
            }
    
            // 方法里面的this, 是谁调用push, this指向谁
            // 这里的this其实就是 Observer 里面 constructor里面的参数data, 在data里面添加一个__ob__属性, 指向类的实例, 就能从this上面获取observeArray了
            if(inserted) {
                ob.observeArray(inserted)
            }
    
            console.log('mrthios:', method)
    
            return result
        }
    })
    
    
    
  4. 浏览器上打开2.array.html 可以显示 使用的是数组的哪个方法, 数组里面的指向被劫持, 新增的对象也被劫持, ok

标签:__,arr,方法,响应,数组,push,原理,data
来源: https://www.cnblogs.com/littlelittleship/p/16403797.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有