<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// vue2对象响应式原理 Object.defineProperty()
// vue2数组响应式原理 覆盖可以修改数组的7个方法
// 从数组原型中获取这7个方法,并覆盖为可以发送更新通知的函数实现
const originalProto = Array.prototype
// 克隆数组原型,复制新的原型对象
const arrayProto = Object.create(originalProto)
const meArr = ['push','pop','shift','unshift','splice','reverse','sort']
meArr.forEach(
method => {
// 做原型数组方法做的事情
arrayProto[method] = function(){
originalProto[method].apply(this,arguments)
// 通知更新
notifyUpdate()
}
}
)
// 思想: 递归遍历传入obj,定义每个属性的拦截
function observe(obj){
if(typeof obj !== 'object' || obj == null){
return
}
// 判断类型,如果是数组就替换他的原型
if(Array.isArray(obj)){
Object.setPrototypeOf(obj,arrayProto)
}else{
// 拿出对象的key值
const keys = Object.keys(obj)
for (let index = 0; index < keys.length; index++) {
const key = keys[index];
// 对obj的每个数据进行拦截
defineReactive(obj,key,obj[key])
}
}
}
// 具体定义指定的key拦截器
function defineReactive(obj,key,val){
// 递归遍历
observe(val)
// val实际上是一个闭包
Object.defineProperty(obj,key,{
get(){
return val
},
set(newVal){
if(newVal !== val){
observe(newVal)
notifyUpdate()
val = newVal
}
}
})
}
function notifyUpdate(){
console.log('页面更新');
}
const data = {foo:'foo',bar:{a:1},arr:[1,2,3]}
observe(data)
// 1普通更新
// data.foo = 'foooooooo'
// 2嵌套对象更新
// data.bar.a = 10
// 3直接赋值对象
// data.bar = {a:10}
// 数组更新
data.arr.push(4)
// vue2的问题分析
// 1需要响应的数据较大时,递归遍历性能不好,消耗较大
// 2新增或删除属性无法监听
// 3数组响应化需要额外实现,导致语法有限制,如数组length无法操作数组,通过$set等方法实现
</script>
</body>
</html>