// Code source: https://github.com/HcySunYang/jsonob/blob/master/src/index.js
// The optimization steps and questions are as follows:
1: bug->The assignment expression and the value in the set method in the observe function The listening expressions are written in the wrong order
2: Optimization -> overrideArrayProto function, no result return value (fakeProperty does not need return value)
3: Question -> Outputting the array, the result is not an array, but'( [ Getter/Setter], [Getter/Setter], [Getter/Setter]]', why is this?
4: Question -> In line 67, isn't this just oldArray? Why use this.slice(0) for assignment, Instead of using this directly?
After contacting the author of hcy, I responded immediately, thank you very much! The reply is as follows:
For the third question, it is because the elements of the array are set as accessor attributes, but all accessor attributes are printed out get/set format. Don't worry about the fourth question, you can check http://hcysun.me/vue-design/art/7vue-reactive.html. There is a complete vue implementation
function log(){
var args = Array.prototype.slice.call(arguments);
console.log.apply(console, args);
}
function isObject(obj){
return Object.prototype.toString.call(obj) === '[object Object]'
}
function isArray(arr){
return Object.prototype.toString.call(arr) === '[object Array]'
}
const OAM = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
class JsonOBJ {
constructor(obj, callback){
if(!isObject(obj) && !isArray(arr)){ //数组也可以侦听
throw new Error('the parameter obj show be object or array!')
}
this.$callback = callback;
this.observe(obj)
}
observe(obj, pathArr){
if(isArray(obj)){
this.overrideArrayProto(obj, pathArr)
}
Object.keys(obj).forEach(ObjKey => {//改为es6语法
//对patharr逻辑进行优化
var tempPathArr = pathArr && pathArr.slice(0) || [];
tempPathArr.push(ObjKey);
const oldVal = obj[ObjKey];
Object.defineProperty(obj, ObjKey, {
get: function(){
return oldVal;
},
set:(function(newVal){
if(oldVal !== newVal){
this.$callback(newVal, oldVal, tempPathArr)
//源代码这里是错误的,应该先赋值,再侦听
oldVal = newVal;
this.observe(oldVal, tempPathArr);
}
}).bind(this)
})
if(isArray(oldVal) || isObject(oldVal)){
this.observe(oldVal, tempPathArr);
}
})
}
overrideArrayProto(arr, pathArr){
const originProto = Array.prototype;
const overrideProto = Object.create(originProto);
const self = this;
//let result://这里不需要result,因为value函数不需要返回值
OAM.forEach(method => {
Object.defineProperty(overrideProto, method, {
value:function(){
const oldVal = this.slice(0);
var arg = [].slice.apply(arguments);
originProto[method].apply(this, arg);
self.observe(this, pathArr);
self.$callback(this, oldVal, pathArr)
},
writable:true,
configurable:true,
enumerable:false
})
})
arr.__proto__ = overrideProto;
}
}
var data = {
a: 200,
level1: {
b: 'str',
c: [[1,2], 2, 3],
level2: {
d: 90
}
}
}
new JsonOBJ(data, log)
// data.level1.b = 'sss';
// data.level1.level2.d = 'msn';
data.level1.c[0].push([5,6]);