網站首頁 編程語言 正文
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
- 上一篇:沒有了
- 下一篇:沒有了
相關推薦
- 2022-06-09 Python列表的索引與切片_python
- 2022-11-18 C++11正則表達式詳解(regex_match、regex_search和regex_replac
- 2023-05-08 Docker中的compose簡介_docker
- 2023-07-05 go gorm想要查詢數據按照where in中的數據進行排序
- 2022-10-18 linux下shell腳本備份文件的方法實現_linux shell
- 2022-03-08 用C語言實現鏈式棧介紹_C 語言
- 2022-12-10 C++的std::vector<bool>轉儲文件問題_C 語言
- 2022-07-13 VMware Workstations 打開.vmx 虛擬機無反應問題
- 欄目分類
-
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支