Fix array un-observe
This commit is contained in:
parent
c506f8d98e
commit
0039ecdd4f
@ -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];
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user