Fix array un-observe

This commit is contained in:
Bartek Fabiszewski 2019-12-14 17:10:19 +01:00
parent c506f8d98e
commit 0039ecdd4f
2 changed files with 81 additions and 16 deletions

View File

@ -81,6 +81,11 @@ export default class uObserve {
}
if (this.isObserved(obj, property)) {
obj._values[property] = value;
if (Array.isArray(obj[property])) {
for (const obs of obj._observers[property]) {
this.observeArray(obj[property], obs);
}
}
} else {
obj[property] = value;
}
@ -110,7 +115,7 @@ export default class uObserve {
uObserve.notify(obj._observers[property], newValue);
}
if (Array.isArray(obj[property])) {
this.observeArray(obj[property], observer);
this.observeArray(obj[property], obj._observers[property]);
}
}
});
@ -139,21 +144,17 @@ export default class uObserve {
/**
* Observe array
* @param {Object} arr
* @param {ObserveCallback} observer
* @param {(ObserveCallback|Set<ObserveCallback>)} observer
*/
static observeArray(arr, observer) {
this.addObserver(arr, observer);
[ 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift' ].forEach(
(operation) => {
const descriptor = Object.getOwnPropertyDescriptor(Array.prototype, operation);
descriptor.value = function () {
const result = Array.prototype[operation].apply(arr, arguments);
console.log(`[${operation}] ` + (arr.length ? `[${arr[0]}, …](${arr.length})` : arr));
uObserve.notify(arr._observers, arr);
return result;
};
Object.defineProperty(arr, operation, descriptor);
});
if (observer instanceof Set) {
for (const obs of observer) {
this.addObserver(arr, obs);
}
} else {
this.addObserver(arr, observer);
}
this.overrideArrayPrototypes(arr, arguments);
}
/**
@ -271,11 +272,32 @@ export default class uObserve {
}
}
static restoreArrayPrototypes(arr) {
/**
* @param {Object} arr
*/
static overrideArrayPrototypes(arr) {
[ 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift' ].forEach(
(operation) => {
const descriptor = Object.getOwnPropertyDescriptor(Array.prototype, operation);
Object.defineProperty(arr, operation, descriptor);
if (!arr.hasOwnProperty(operation)) {
descriptor.value = function () {
const result = Array.prototype[operation].apply(arr, arguments);
console.log(`[${operation}] ` + (arr.length ? `[${arr[0]}, …](${arr.length})` : arr));
uObserve.notify(arr._observers, arr);
return result;
};
Object.defineProperty(arr, operation, descriptor);
}
});
}
/**
* @param {Object} arr
*/
static restoreArrayPrototypes(arr) {
[ 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift' ].forEach(
(operation) => {
delete arr[operation];
});
}

View File

@ -157,6 +157,8 @@ describe('Observe tests', () => {
it('should retain observers after array is reassigned', () => {
// given
let result2 = false;
let resultValue2;
const array = [ 1, 2 ];
const newArray = [ 3, 4 ];
object = { array: array };
@ -164,15 +166,56 @@ describe('Observe tests', () => {
result = true;
resultValue = value;
});
uObserve.observe(object, 'array', (value) => {
result2 = true;
resultValue2 = value;
});
// when
object.array = newArray;
result = false;
result2 = false;
expect(result).toBe(false);
expect(result2).toBe(false);
object.array.push(5);
// then
expect(result).toBe(true);
expect(result2).toBe(true);
expect(resultValue).toEqual(newArray);
// noinspection JSUnusedAssignment
expect(resultValue2).toEqual(newArray);
});
it('should retain observers after array property is silently set', () => {
// given
let result2 = false;
let resultValue2;
const array = [ 1, 2 ];
const newArray = [ 3, 4 ];
object = { array: [] };
uObserve.observe(object, 'array', (value) => {
result = true;
resultValue = value;
});
uObserve.observe(object, 'array', (value) => {
result2 = true;
resultValue2 = value;
});
// when
uObserve.setSilently(object, 'array', array);
object.array = newArray;
result = false;
result2 = false;
expect(result).toBe(false);
expect(result2).toBe(false);
object.array.push(5);
// then
expect(result).toBe(true);
expect(result2).toBe(true);
expect(resultValue).toEqual(newArray);
// noinspection JSUnusedAssignment
expect(resultValue2).toEqual(newArray);
});
});