日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Object.defineProperty和Proxy分別實現響應式原理的簡單示例

作者:qq_42750608 更新時間: 2023-10-10 編程語言

1. 利用Object.defineProperty+遞歸 實現響應式原理

// 監聽數組, Object.defineProperty做不到, 所以需要重寫數組方法!!!
// 重新定義數組原型
const oldArrProperty = Array.prototype
// 創建新對象, 原型指向oldArrProperty, 再擴展新的方法不會影響Array原型
// 使用Object.create是為了不污染全局的原型方法
const arrProto = Object.create(oldArrProperty);
['push', 'pop', 'shift', 'unshift', 'splice'].forEach(element => {
    arrProto[element] = function () {
        updateView(); // 觸發視圖更新
        oldArrProperty[element].call(this, ...arguments);
    }
});

// 監聽對象屬性
function observer(target) {
    if (typeof target !== 'object' || target === null) {
        // 不是對象或數組
        return target;
    }

    if (Array.isArray(target)) {
        target.__proto__ = arrProto
    }

    // 重新定義各個屬性(for in 也可以遍歷數組)
    for (let key in target) {
        defineReactive(target, key, target[key])
    }
}

// 重新定義屬性, 監聽起來
function defineReactive(target, key, value) {
    // 深度監聽(深層對象):
    observer(value);

    // 核心API
    Object.defineProperty(target, key, {
        get() {
            return value
        },
        set(newVal) {
            if (newVal !== value) {
                // 設置新值的時候也要深度監聽(深層對象):
                observer(newVal)
                // 設置新值
                // 注意, value一直閉包中, 此處設置完之后, 再get時也是會獲取最新的值
                value = newVal

                // 觸發更新視圖
                updateView();
            }
        }
    })
}

// 觸發更新視圖
function updateView() {
    console.log('視圖更新')
}
const data = {
    name: 'zhangsan',
    age: 20,
    info: {
        city: '北京', // 需要深度監聽
    },
    nums: []
}

// 監聽數據
observer(data)

//測試
// data.name='sdhewifewfewfewf'
// data.age = 21
// data.info.city = 'shanghai'
// data.x = '100';//新增屬性, 監聽不到--所以有V
// delete data.name; // 刪除屬性, 監聽不到 --所以有Vue.delete
data.nums.push({ a: 1 }); // 監聽數組
data.nums[0].a = 222
// console.log(data.name, data.age, data.info.city, data.nums)


// console.log(arrProto)
// console.log(arrProto.__proto__.push)
// console.log(arrProto.__proto__ === oldArrProperty)
// console.log(arrProto.prototype.constructor)

測試: 每次修改數據, 查看控制臺有沒有隨著數據變化打印"視圖更新"

2. 使用Proxy和Reflect實現響應式原理, 如果有深層對象和數組也需要遞歸

var data = {
    name: 'zhangsan',
    age: 20,
    list: [1, 2],
    obj: { a: 1, b: 2, c: 2, city: {
        name: '北京' 
    }}
}

function reactive(data) {
    const config = {
        // receiver其實指的就是Proxy
        get(target, key, receiver) {
            // Reflect.ownKeys可以獲取不是原型上的屬性
            const ownKeys = Reflect.ownKeys(target);
            // 只處理本身(非原型的)屬性
            // if(ownKeys.includes(key)) {
            //     console.log('get:', key, '本身(非原型的)屬性');
            // }
            const result = Reflect.get(target, key, receiver);
            // 如果對象有深層的對象或者數組, 需要遞歸
            if(Array.isArray(result) || Object.prototype.toString.call(result) === '[object Object]') {
                return reactive(result);
            }
            console.log('get:', key, target[key], result)
            return result;
        },
        set(target, key, val, receiver) {
            // 重復的數據不處理
            const oldVal = target[key]
            if(val === oldVal) {
                return true
            }

            const ownKeys = Reflect.ownKeys(target);
            // 只處理本身(非原型的)屬性
            if(ownKeys.includes(key)) { // push方法就不執行了
                console.log('get:', key, '已有的key');
            }
            else {
                console.log('get:', key, '新增的key');
            }

            const result = Reflect.set(target, key, val, receiver);
            console.log('set:', key, val, result)
            // 觸發更新視圖
            updateView();
            return result;
        },
        deleteProperty(target, key) {
            const result = Reflect.deleteProperty(target, key);
            console.log('deleteProperty:', key, result)
            // 觸發更新視圖
            updateView();
            return result;
        },
    }
    const proxyData = new Proxy(data, config);
    return proxyData
}  

// 觸發更新視圖
function updateView() {
    console.log('視圖更新')
}

const  proxyData = reactive(data)
proxyData.list.push('13')
proxyData.obj.a = 999
proxyData.obj.b = undefined
proxyData.obj.city.name = 'shanghai'
Reflect.deleteProperty(proxyData.obj, 'c')
proxyData.obj.d = 'ddddd'

測試: 每次修改數據, 查看控制臺有沒有隨著數據變化打印"視圖更新"

原文鏈接:https://blog.csdn.net/qq_42750608/article/details/133612535

  • 上一篇:沒有了
  • 下一篇:沒有了
欄目分類
最近更新