Object.defineProperty 应用
const data = {};
let name = 'hello';
Object.defineProperty(data, 'name', {
get: function() {
console.log('>>> get');
return name;
},
set: function(newVal) {
name = newVal;
// 更新视图
console.log('>>> 更新视图');
}
})
data.name; // >>> get
data.name = 'world'; // >>> 更新视图
基本实现
const data = {
name: 'zhangsan',
age: 28
}
observer(data)
function observer(target) {
if (typeof target !== 'object' || target === null) {
return target;
}
for (let key in target) {
defineReactive(target, key, target[key]);
}
}
function defineReactive(target, key, value) {
Object.defineProperty(target, key, {
get() {
return value;
},
set(newVal) {
if(newVal !== value) {
value = newVal;
console.log('>>> 更新视图')
}
}
})
}
data.name = 'lisi' // >>> 更新视图
实现深度监听
const data = {
name: 'zhangsan',
age: 28,
friend: {
name: 'wangwu'
}
}
observer(data)
function observer(target) {
if (typeof target !== 'object' || target === null) {
return target;
}
for (let key in target) {
defineReactive(target, key, target[key]);
}
}
function defineReactive(target, key, value) {
observer(value) // 实现深度监听
Object.defineProperty(target, key, {
get() {
return value;
},
set(newVal) {
if(newVal !== value) {
value = newVal;
console.log('>>> 更新视图')
}
}
})
}
data.friend.name = 'wangwu2' // >>> 更新视图
监听增加的数据层级
const data = {
name: 'zhangsan',
age: 28,
}
observer(data)
function observer(target) {
if (typeof target !== 'object' || target === null) {
return target;
}
for (let key in target) {
defineReactive(target, key, target[key]);
}
}
function defineReactive(target, key, value) {
observer(value)
Object.defineProperty(target, key, {
get() {
return value;
},
set(newVal) {
observer(newVal) // 监听新增的对象属性
if(newVal !== value) {
value = newVal;
console.log('>>> 更新视图')
}
}
})
}
data.age = { number: 25} // >>> 更新视图
data.age.number = 27 // >>> 更新视图
数组方法响应式实现
const oldArrayProto = Array.prototype;
const newArrayProto = Object.create(oldArrayProto);
['push', 'pop', 'shift', 'unshift', 'splice'].forEach((method) => {
oldArrayProto[method].call(this, ...arguments);
console.log('更新视图');
})
function observer(target) {
if (typeof target !== 'object' || target === null) {
return target;
}
if (Array.isArray(target)) {
target.__proto__ = newArrayProto; // 修改数组实例的原型
}
for (let key in target) {
defineReactive(target, key, target[key]);
}
}
function defineReactive(target, key, value) {
...
}
vue2 实现响应式的不足
- 数据层级很深的时候,一开始就需要设置全部数据的监听,很费性能;
- data 新增或者删除属性不能监听到;
- 数组方法不能原生实现监听,需要额外处理;