需要的基础知识
需要了解一些底层的知识才能往下走哦,请前往另一个博客
基本思想
对象 Object
对于 object ,就是改变这个对象的属性,通过重写这个属性的 get 和 set
就可以在 set 里面进行需要的操作
当一个属性被赋值时,我们在 set 的时候去做一些其他的操作
比如发送某一个事件,告诉外部这个变量发生了改变,这个就是 Mvvm 框架所使用的
数组 Array
对于数组,我们需要对数组里面的对象监听变化,即遍历数组,并使用上面的方法
而数组整个的变化,我们也需要监听
比如数组的 push() , pop() 这种会改变数组内容的重要方法
我们也必须通知到位,跟劫持对象的属性一样
劫持对象的属性用 get 和 set
对于数组我们就重写他的方法即可
实现 JsonOb
/**
* 实现动态绑定的核心部分,
* 每次修改属性值,都会调用对应函数,并且获取值的路径
*/
const OP = Object.prototype;
const types = {
obj: '[object Object]',
array: '[object Array]'
}
const OAM = ['push', 'pop', 'shift', 'unshift', 'sort', 'reverse', 'splice'];
/**
* 实现属性拦截的类
*/
export class JsonOb<T> {
constructor(obj:T, callback: (newVal: any, oldVal: any, pathArray: string[]) => void) {
if (OP.toString.call(obj) !== types.obj && OP.toString.call(obj) !== types.array) {
console.error('请传入一个对象或数组');
}
this._callback = callback;
this.observe(obj);
}
private _callback;
/**对象属性劫持 */
private observe<T>(obj: T, path?) {
if (OP.toString.call(obj) === types.array) {
this.overrideArrayProto(obj, path);
}
Object.keys(obj).forEach((key) => {
let self = this;
let oldVal = obj[key];
let pathArray = path && path.slice();
if (pathArray) {
pathArray.push(key);
}
else {
pathArray = [key];
}
Object.defineProperty(obj, key, {
get: function () {
return oldVal;
},
set: function (newVal) {
//cc.log(newVal);
if (oldVal !== newVal) {
if (OP.toString.call(newVal) === '[object Object]') {
self.observe(newVal, pathArray);
}
self._callback(newVal, oldVal, pathArray)
oldVal = newVal
}
}
})
if (OP.toString.call(obj[key]) === types.obj || OP.toString.call(obj[key]) === types.array) {
this.observe(obj[key], pathArray)
}
}, this)
}
/**
* 对数组类型进行动态绑定
* @param array
* @param path
*/
private overrideArrayProto(array: any, path)